diff --git a/build.gradle b/build.gradle index 2936ac92..22dd7a19 100644 --- a/build.gradle +++ b/build.gradle @@ -53,6 +53,9 @@ dependencies { implementation 'org.webjars:jquery:3.1.0' implementation 'com.squareup.okhttp3:okhttp:4.9.3' implementation 'com.googlecode.json-simple:json-simple:1.1.1' + implementation 'com.fasterxml.jackson.core:jackson-core:2.14.2' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.14.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.2' implementation files('lib/RuleUtils.jar') implementation('org.opencds.cqf:cql-engine:1.3.12.1') { diff --git a/src/main/java/org/hl7/davinci/priorauth/ClaimResponseFactory.java b/src/main/java/org/hl7/davinci/priorauth/ClaimResponseFactory.java index a84865ec..85814381 100644 --- a/src/main/java/org/hl7/davinci/priorauth/ClaimResponseFactory.java +++ b/src/main/java/org/hl7/davinci/priorauth/ClaimResponseFactory.java @@ -1,5 +1,6 @@ package org.hl7.davinci.priorauth; +import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -9,13 +10,20 @@ import java.util.UUID; import java.util.logging.Logger; import java.util.Random; +import com.fasterxml.jackson.core.*; +import org.springframework.core.io.ClassPathResource; //import org.springframework.core.io.Resource; import org.springframework.core.io.DefaultResourceLoader; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.type.TypeReference; + import org.hl7.davinci.priorauth.Database.Table; import org.hl7.davinci.priorauth.FhirUtils.Disposition; import org.hl7.davinci.priorauth.FhirUtils.ReviewAction; +import org.hl7.davinci.rules.RequestMapping; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Claim; @@ -48,6 +56,8 @@ public class ClaimResponseFactory { static final Logger logger = PALogger.getLogger(); static final String TEMP_REQUEST_CODE = "73722"; static final String TEMP_REQUEST_SYSTEM = "http://www.ama-assn.org/go/cpt"; + + //Resource mappingTable = resourceLoader.getResource("requestMappingTable.json"); /** * Generate a new ClaimResponse and store it in the database. * @@ -136,20 +146,77 @@ public static Bundle generateAndStoreClaimResponse(Bundle bundle, Claim claim, S } public static boolean ItemRequiresFollowup(ItemComponent item) { + + // TODO, this is not very effective and reloads the file every time (because it is a static function. Needs some rework boolean hasRequestTrigger = false; + List requestMapping = new ArrayList(); + + + //ObjectMapper objectMapper = new ObjectMapper(); + // TODO: This should not have to be loaded for each call. Doing now for static functions, but needs to be fixed. + // This mapping has to be used for several uses beyond this function + //DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); + + + try(InputStream in=Thread.currentThread().getContextClassLoader().getResourceAsStream("requestMappingTable.json")){ + ObjectMapper mapper = new ObjectMapper(); + requestMapping = mapper.readValue(in, new TypeReference>() {}); + } + catch(Exception e){ + + logger.info("Exception on ItemRequiresFollowup :" + e.getMessage()); + } + + for(Coding procedureCoding : item.getProductOrService().getCoding()) { - // TODO: change to configuration file driven check. See file resources/requestMappingTable - if(procedureCoding.getCode().equals(TEMP_REQUEST_CODE) && procedureCoding.getSystem().equals(TEMP_REQUEST_SYSTEM)) + for(RequestMapping mapping : requestMapping) + { + if(procedureCoding.getCode().equals(mapping.getProductOrService().getCode()) && procedureCoding.getSystem().equals(mapping.getProductOrService().getSystem())) + { + logger.info("Found a pending information Request Procedure Code"); + hasRequestTrigger = true; + break; + } + + } + if(hasRequestTrigger == true) { - logger.info("Found a pending information Request Procedure Code"); - hasRequestTrigger = true; break; } } return hasRequestTrigger; } + public static RequestMapping GetRequestMapping(ItemComponent item) + { + RequestMapping request = new RequestMapping(); + List requestMapping = new ArrayList(); + + try(InputStream in=Thread.currentThread().getContextClassLoader().getResourceAsStream("requestMappingTable.json")){ + ObjectMapper mapper = new ObjectMapper(); + requestMapping = mapper.readValue(in, new TypeReference>() {}); + } + catch(Exception e){ + + logger.info("Exception on GetRequestMapping :" + e.getMessage()); + } + + for(Coding procedureCoding : item.getProductOrService().getCoding()) + { + for(RequestMapping mapping : requestMapping) + { + if(procedureCoding.getCode().equals(mapping.getProductOrService().getCode()) && procedureCoding.getSystem().equals(mapping.getProductOrService().getSystem())) + { + logger.info("Found a pending information Request Procedure Code"); + request = mapping; + break; + } + } + } + return request; + } + /** * Create the Bundle for a ClaimResponse * @param requestBundle - the Claim request Bundle @@ -367,10 +434,11 @@ private static CommunicationRequest createCommunicationRequest(Claim claim, Clai { if(ItemRequiresFollowup(item)) { + RequestMapping request = GetRequestMapping(item); CommunicationRequestPayloadComponent crPayload = new CommunicationRequestPayloadComponent(); crPayload.addExtension(FhirUtils.PAYLOAD_SERVICE_LINE_NUMBER, new PositiveIntType(item.getSequence())); // TODO, this needs to be loaded from the request mapping table - crPayload.addExtension(FhirUtils.PAYLOAD_CONTENT_MODIFIER, new CodeableConcept(new Coding("http://loinc.org", "18748-4", "Diagnostic imaging study"))); + crPayload.addExtension(FhirUtils.PAYLOAD_CONTENT_MODIFIER, new CodeableConcept(new Coding(request.getContentModifier().getSystem(), request.getContentModifier().getCode(), request.getContentModifier().getDisplay()))); for(DiagnosisComponent diagnosis : claim.getDiagnosis()) { @@ -455,10 +523,11 @@ else if(item.hasServicedPeriod()) if(action == ReviewAction.PENDEDFOLLOWUP) { + RequestMapping request = GetRequestMapping(item); // TODO, The item trace number should be mapped from the request mapping table Identifier traceIdentifier = new Identifier(); - traceIdentifier.setSystem("http://example.org/payer/PATIENT_EVENT_LINE_TRACE_NUMBER"); - traceIdentifier.setValue("1111111"); + traceIdentifier.setSystem(request.getTraceNumber().getSystem()); + traceIdentifier.setValue(request.getTraceNumber().getCode()); itemComponent.addExtension(FhirUtils.ITEM_TRACE_NUMBER_EXTENSION_URL, traceIdentifier); adjudicationReviewItemExtension.addExtension(FhirUtils.REVIEW_REASON_CODE, new Coding("https://codesystem.x12.org/external/886", "OS", "Open, Waiting for Supplier Feedback")); diff --git a/src/main/java/org/hl7/davinci/rules/RequestMapping.java b/src/main/java/org/hl7/davinci/rules/RequestMapping.java new file mode 100644 index 00000000..8b6d4bb5 --- /dev/null +++ b/src/main/java/org/hl7/davinci/rules/RequestMapping.java @@ -0,0 +1,29 @@ +package org.hl7.davinci.rules; + +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.Identifier; +import org.hl7.fhir.r4.model.StringType; + +// TODO, The TraceNumber should be an Identifier type, but this results in a conflict +// Exception on ItemRequiresFollowup :Conflicting setter definitions for property "referenceElement": org.hl7.fhir.r4.model.Reference#setReferenceElement(org.hl7.fhir.instance.model.api.IIdType) vs org.hl7.fhir.r4.model.Reference#setReferenceElement(org.hl7.fhir.r4.model.StringType) +// To fix this, Identifier probably would need to be extended and override the setter method and annotate it with @JsonIgnore or @com.fasterxml.jackson.annotation.JsonSetter +// See https://stackoverflow.com/questions/37452689/how-to-overcome-conflicting-setter-definitions-for-property + +public class RequestMapping { + private Coding productOrService; + private Coding contentModifier; + private Coding traceNumber; + private StringType questionnaireURL; + + public Coding getProductOrService() { return productOrService; } + public void setProductOrService(Coding value) { this.productOrService = value; } + + public Coding getContentModifier() { return contentModifier; } + public void setContentModifier(Coding value) { this.contentModifier = value; } + + public Coding getTraceNumber() { return traceNumber; } + public void setTraceNumber(Coding value) { this.traceNumber = value; } + + public StringType getQuestionnaireURL() { return questionnaireURL; } + public void setQuestionnaireURL(StringType value) { this.questionnaireURL = value; } +} diff --git a/src/main/resources/requestMappingTable.json b/src/main/resources/requestMappingTable.json index 10ad3124..923c9c7f 100644 --- a/src/main/resources/requestMappingTable.json +++ b/src/main/resources/requestMappingTable.json @@ -10,7 +10,23 @@ "display": "Diagnostic imaging study" }, "traceNumber": { - "identifier": "1111111", + "code": "1111111", + "system": "http://example.org/payer/PATIENT_EVENT_LINE_TRACE_NUMBER" + }, + "questionnaireURL": "" + }, + { + "productOrService": { + "code": "73720", + "system": "http://www.ama-assn.org/go/cpt" + }, + "contentModifier": { + "code": "18748-3", + "system": "http://loinc.org|http://lonc.org", + "display": "Diagnostic imaging study" + }, + "traceNumber": { + "code": "1111112", "system": "http://example.org/payer/PATIENT_EVENT_LINE_TRACE_NUMBER" }, "questionnaireURL": ""