Skip to content

Commit b0dddfb

Browse files
BFD-4665: Add default provider fallback to EOB for claims missing provider data (#3235)
1 parent ca5cb7f commit b0dddfb

9 files changed

Lines changed: 105 additions & 20 deletions

File tree

apps/bfd-pipeline-idr/test_samples2/SYNTHETIC_CLM.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CLM_DT_SGNTR_SK,CLM_UNIQ_ID,CLM_RLT_COND_SGNTR_SK,CLM_TYPE_CD,CLM_SRC_ID,META_SRC_SK,CLM_FROM_DT,CLM_THRU_DT,CLM_CNTL_NUM,CLM_NUM_SK,CLM_EFCTV_DT,CLM_IDR_LD_DT,CLM_OBSLT_DT,GEO_BENE_SK,BENE_SK,CLM_DISP_CD,CLM_QUERY_CD,CLM_ADJSTMT_TYPE_CD,CLM_BILL_FAC_TYPE_CD,CLM_BILL_CLSFCTN_CD,CLM_BILL_FREQ_CD,CLM_CNTRCTR_NUM,CLM_NCH_PRMRY_PYR_CD,CLM_FINL_ACTN_IND,CLM_LTST_CLM_IND,PRVDR_BLG_PRVDR_NPI_NUM,PRVDR_ATNDG_PRVDR_NPI_NUM,PRVDR_OPRTG_PRVDR_NPI_NUM,PRVDR_OTHR_PRVDR_NPI_NUM,PRVDR_RNDRNG_PRVDR_NPI_NUM,CLM_BLG_PRVDR_OSCAR_NUM,CLM_MDCR_COINSRNC_AMT,CLM_BLG_PRVDR_ZIP5_CD,CLM_SBMT_CHRG_AMT,CLM_PMT_AMT,CLM_MDCR_DDCTBL_AMT,CLM_NCVRD_CHRG_AMT,CLM_BLOOD_LBLTY_AMT,CLM_BENE_PMT_COINSRNC_AMT,CLM_BLOOD_CHRG_AMT,CLM_BLOOD_NCVRD_CHRG_AMT,CLM_COB_PTNT_RESP_AMT,CLM_PRVDR_INTRST_PD_AMT,CLM_PRVDR_OTAF_AMT,CLM_PRVDR_RMNG_DUE_AMT,CLM_TOT_CNTRCTL_AMT,CLM_BLOOD_PT_FRNSH_QTY,PRVDR_RFRG_PRVDR_NPI_NUM,CLM_PRVDR_PMT_AMT,CLM_RIC_CD,CLM_BLG_PRVDR_NPI_NUM,CLM_RFRG_PRVDR_PIN_NUM,CLM_ALOWD_CHRG_AMT,CLM_BENE_PD_AMT,CLM_BENE_PMT_AMT,CLM_BENE_INTRST_PD_AMT,CLM_ORIG_CNTL_NUM,PRVDR_SRVC_PRVDR_NPI_NUM,CLM_PD_DT,PRVDR_PRSCRBNG_PRVDR_NPI_NUM,CLM_SBMT_FRMT_CD,CLM_SBMTR_CNTRCT_NUM,CLM_SBMTR_CNTRCT_PBP_NUM,CLM_OTHR_TP_PD_AMT,IDR_INSRT_TS,IDR_UPDT_TS,CLM_ATNDG_PRVDR_NPI_NUM,CLM_OPRTG_PRVDR_NPI_NUM,CLM_OTHR_PRVDR_NPI_NUM,CLM_RNDRG_PRVDR_NPI_NUM,CLM_SRVC_PRVDR_GNRC_ID_NUM,PRVDR_SRVC_ID_QLFYR_CD,PRVDR_PRSBNG_ID_QLFYR_CD,CLM_ATNDG_FED_PRVDR_SPCLTY_CD,GEO_BLG_SSA_STATE_CD,CLM_PD_STUS_CD
2-
322823692140,1071939711294,673069517797,40,20000,7,2021-09-26,2021-10-03,67289832423923BIX,1,2025-05-30,2025-05-30,9999-12-31,86974,178083966,55,3,0,3,3,X,01211,L,Y,Y,1104867175,1437702123,1942945159,1972944437,1558719914,001500,0.83,77550,815173.1329847890098,625244.33,776.87,189928.8,8.66,544.3189236473176,,,360.5390326439280,609.69,312.97,854.41,243.4283926422387,0,,20.35,,,,916765.7358968634376,,225008.17,,,,9999-12-31,,,,,,2025-12-26 19:21:50.538903,,,,,,,,,A0,03
2+
322823692140,1071939711294,673069517797,40,20000,7,2021-09-26,2021-10-03,67289832423923BIX,1,2025-05-30,2025-05-30,9999-12-31,86974,178083966,55,3,0,3,3,X,01211,L,Y,Y,,,,,,001500,0.83,77550,815173.1329847890098,625244.33,776.87,189928.8,8.66,544.3189236473176,,,360.5390326439280,609.69,312.97,854.41,243.4283926422387,0,,20.35,,,,916765.7358968634376,,225008.17,,,,9999-12-31,,,,,,2025-12-26 19:21:50.538903,,,,,,,,,A0,03
33
322823692141,1071939711295,,10,20000,7,2021-09-26,2021-10-03,67289832423923BIX,1,2025-05-30,2025-05-30,9999-12-31,86974,181968400,55,3,0,3,3,X,01211,L,Y,Y,1104867175,1437702123,1942945159,1972944437,1558719914,001500,0.83,77005,815173.13,625244.33,776.8698768765123,189928.8,8.6587654578765,,6.9911829076291,77.3,151.2789573902381,377.9276567879876,96.6890386948091,,207.0781097280107,0,,,,,,916765.73,,225008.1723456788765,,,,9999-12-31,,,,,,2026-01-11 04:43:44.721156,,,,,,,,,A0,03
44
322823692142,1071939711296,616234798483,40,20000,7,2021-09-26,2021-10-03,67289832423923BIX,1,2025-05-30,2025-05-30,9999-12-31,86974,181968400,55,3,0,3,3,X,01211,L,Y,Y,1104867175,1437702123,1942945159,1972944437,1558719914,001500,0.83,75205,815173.13,625244.33,776.87,189928.8,8.66,694.2593027489236,,,95.82,180.88,523.7798679801093,393.0490172830912,8569.4,0,,11.09,,,,82490.85,,450536.56,,,,9999-12-31,,,,,,2025-07-13 04:05:01.400693,2025-08-20 03:57:55.730556,,,,,,,,A0,03
55
322823692143,1071939711297,1699821257,1013,21000,1003,2021-09-26,2021-10-03,67289832423923BIX,1,2025-05-30,2025-05-30,9999-12-31,86974,181968400,55,3,~,3,3,X,01211,,N,Y,1104867175,1437702123,1942945159,1972944437,1558719914,001500,0.83,,815173.13,625244.33,776.87,189928.8,8.66,,,,,,,,,,,,,,,82490.85,,450536.56,,,,9999-12-31,,,,,,,,,,,,,,,A0,03,I

apps/bfd-server-ng/src/main/java/gov/cms/bfd/server/ng/claim/model/common/ProviderFhirHelper.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ public static Reference createProviderReferenceWithQualifier(
113113
return reference;
114114
}
115115

116+
/**
117+
* Creates a FHIR {@link Identifier} for a provider (Practitioner or Organization), or member of
118+
* the care-team.
119+
*
120+
* @param npiNumber the provider's identifier value
121+
* @return a simple FHIR provider {@link Identifier} instance
122+
*/
116123
private static Identifier createNpiIdentifier(String npiNumber) {
117124
return new Identifier()
118125
.setSystem(SystemUrls.NPI)

apps/bfd-server-ng/src/main/java/gov/cms/bfd/server/ng/claim/model/institutional/entities/ClaimInstitutionalBase.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package gov.cms.bfd.server.ng.claim.model.institutional.entities;
22

3-
import static gov.cms.bfd.server.ng.claim.model.common.ClaimDiagnosisType.*;
3+
import static gov.cms.bfd.server.ng.claim.model.common.ClaimDiagnosisType.FIRST;
44

55
import gov.cms.bfd.server.ng.ClaimFilterOptions;
66
import gov.cms.bfd.server.ng.claim.model.common.AdjudicationChargeBase;
@@ -26,12 +26,15 @@
2626
import gov.cms.bfd.server.ng.claim.model.institutional.ReferringInstitutionalCareTeam;
2727
import gov.cms.bfd.server.ng.claim.model.institutional.RenderingCareTeam;
2828
import gov.cms.bfd.server.ng.claim.model.institutional.TypeOfBillCode;
29+
import gov.cms.bfd.server.ng.util.FhirUtil;
2930
import gov.cms.bfd.server.ng.util.SequenceGenerator;
3031
import jakarta.persistence.Column;
3132
import jakarta.persistence.Embedded;
3233
import jakarta.persistence.MappedSuperclass;
3334
import java.math.BigDecimal;
34-
import java.util.*;
35+
import java.util.Collection;
36+
import java.util.List;
37+
import java.util.Optional;
3538
import java.util.stream.Stream;
3639
import lombok.Getter;
3740
import org.hl7.fhir.r4.model.ExplanationOfBenefit;
@@ -182,11 +185,12 @@ private void addDiagnoses(ExplanationOfBenefit eob) {
182185
private void addProviders(ExplanationOfBenefit eob) {
183186
getBillingProviderHistory()
184187
.toFhirNpiType()
185-
.ifPresent(
188+
.ifPresentOrElse(
186189
p -> {
187-
eob.addContained(p);
188190
eob.setProvider(new Reference("#" + p.getId()));
189-
});
191+
eob.addContained(p);
192+
},
193+
() -> eob.setProvider(FhirUtil.setDataAbsentReasonUnknown(new Reference())));
190194
}
191195

192196
private void addAllSupportingInfo(ExplanationOfBenefit eob) {

apps/bfd-server-ng/src/main/java/gov/cms/bfd/server/ng/claim/model/professional/entities/ClaimProfessionalBase.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,17 @@
1313
import gov.cms.bfd.server.ng.claim.model.professional.BillingProviderProfessional;
1414
import gov.cms.bfd.server.ng.claim.model.professional.ClinicalTrialNumber;
1515
import gov.cms.bfd.server.ng.claim.model.professional.ReferringProfessionalCareTeam;
16+
import gov.cms.bfd.server.ng.util.FhirUtil;
1617
import gov.cms.bfd.server.ng.util.SequenceGenerator;
1718
import jakarta.persistence.Column;
1819
import jakarta.persistence.Embedded;
1920
import jakarta.persistence.MappedSuperclass;
20-
import java.util.*;
21+
import java.util.ArrayList;
22+
import java.util.Collection;
23+
import java.util.HashMap;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Optional;
2127
import java.util.stream.Stream;
2228
import lombok.Getter;
2329
import org.hl7.fhir.r4.model.ExplanationOfBenefit;
@@ -135,11 +141,12 @@ private void addClaimItemToEob(
135141
private void addProviders(ExplanationOfBenefit eob) {
136142
getBillingProviderHistory()
137143
.toFhirNpiType()
138-
.ifPresent(
144+
.ifPresentOrElse(
139145
p -> {
140-
eob.addContained(p);
141146
eob.setProvider(new Reference("#" + p.getId()));
142-
});
147+
eob.addContained(p);
148+
},
149+
() -> eob.setProvider(FhirUtil.setDataAbsentReasonUnknown(new Reference())));
143150
}
144151

145152
private void addAllSupportingInfo(ExplanationOfBenefit eob) {

apps/bfd-server-ng/src/main/java/gov/cms/bfd/server/ng/claim/model/rx/entities/ClaimCmsRx.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import gov.cms.bfd.server.ng.claim.model.rx.ServiceProviderPharmacy;
2323
import gov.cms.bfd.server.ng.claim.model.rx.SubmitterContractNumber;
2424
import gov.cms.bfd.server.ng.claim.model.rx.SubmitterContractPBPNumber;
25+
import gov.cms.bfd.server.ng.util.FhirUtil;
2526
import gov.cms.bfd.server.ng.util.SequenceGenerator;
2627
import gov.cms.bfd.server.ng.util.SystemUrls;
2728
import jakarta.persistence.Column;
@@ -103,11 +104,12 @@ private void addClaimLineItem(ExplanationOfBenefit eob, ClaimFilterOptions optio
103104
private void addServiceProvider(ExplanationOfBenefit eob) {
104105
serviceProviderHistory
105106
.toFhirNpiType()
106-
.ifPresent(
107+
.ifPresentOrElse(
107108
p -> {
108-
eob.addContained(p);
109109
eob.setProvider(new Reference("#" + p.getId()));
110-
});
110+
eob.addContained(p);
111+
},
112+
() -> eob.setProvider(FhirUtil.setDataAbsentReasonUnknown(new Reference())));
111113
}
112114

113115
private void addSupportingInfo(ExplanationOfBenefit eob) {

apps/bfd-server-ng/src/main/java/gov/cms/bfd/server/ng/util/FhirUtil.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
import java.util.regex.Pattern;
1010
import java.util.stream.Collectors;
1111
import java.util.stream.Stream;
12+
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
1213
import org.hl7.fhir.r4.model.Bundle;
14+
import org.hl7.fhir.r4.model.CodeType;
1315
import org.hl7.fhir.r4.model.CodeableConcept;
14-
import org.hl7.fhir.r4.model.Coding;
1516
import org.hl7.fhir.r4.model.Meta;
17+
import org.hl7.fhir.r4.model.Reference;
1618
import org.hl7.fhir.r4.model.Resource;
19+
import org.hl7.fhir.r4.model.codesystems.DataAbsentReason;
1720
import org.springframework.web.util.UriComponentsBuilder;
1821

1922
/** FHIR-related utility methods. */
@@ -25,22 +28,44 @@ private FhirUtil() {}
2528
private static final String START_INDEX_PARAM = "startIndex";
2629

2730
/**
28-
* Adds a data absent reason of the coding is empty.
31+
* Adds a data absent reason if the coding is empty.
2932
*
3033
* @param codeableConcept codeable concept
3134
* @return modified codeable concept
3235
*/
3336
public static CodeableConcept checkDataAbsent(CodeableConcept codeableConcept) {
3437
if (codeableConcept.getCoding().isEmpty()) {
35-
return codeableConcept.addCoding(
36-
new Coding()
37-
.setSystem(SystemUrls.HL7_DATA_ABSENT)
38-
.setCode("not-applicable")
39-
.setDisplay("Not Applicable"));
38+
setDataAbsentReason(codeableConcept, DataAbsentReason.NOTAPPLICABLE);
4039
}
4140
return codeableConcept;
4241
}
4342

43+
/**
44+
* Convenience method for Reference calls for data-absent-reason. prior logic should determine
45+
* data-absent-reason is necessary.
46+
*
47+
* @param ref fhir CodeableConcept IBaseHasExtensions is common throughout FHIR elements.
48+
* @return modified Reference
49+
*/
50+
public static Reference setDataAbsentReasonUnknown(Reference ref) {
51+
setDataAbsentReason(ref, DataAbsentReason.UNKNOWN);
52+
return ref;
53+
}
54+
55+
/**
56+
* Adds a data absent reason extension with valueCode to the fhirElement; prior logic should
57+
* determine data-absent-reason is necessary.
58+
*
59+
* @param fhirElement implements IBaseHasExtensions is common throughout FHIR elements.
60+
* @param dataAbsentReason selected DataAbsentReason
61+
*/
62+
public static void setDataAbsentReason(
63+
IBaseHasExtensions fhirElement, DataAbsentReason dataAbsentReason) {
64+
var extension = fhirElement.addExtension();
65+
extension.setUrl(SystemUrls.HL7_STRUCTURE_DEFINITION_DATA_ABSENT);
66+
extension.setValue(new CodeType().setValue(dataAbsentReason.toCode()));
67+
}
68+
4469
/**
4570
* Returns the matching HCPCS system.
4671
*

apps/bfd-server-ng/src/main/java/gov/cms/bfd/server/ng/util/SystemUrls.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,13 @@ private SystemUrls() {
708708
public static final String SAMHSA_ACT_CODE_SYSTEM_URL =
709709
"http://terminology.hl7.org/CodeSystem/v3-ActCode";
710710

711+
/**
712+
* <a href="http://hl7.org/fhir/extensions/StructureDefinition-data-absent-reason.html">HL7
713+
* Structure Definition Data Absent Reason.</a>
714+
*/
715+
public static final String HL7_STRUCTURE_DEFINITION_DATA_ABSENT =
716+
"http://hl7.org/fhir/StructureDefinition/data-absent-reason";
717+
711718
// US Core
712719
/**
713720
* <a href="https://hl7.org/fhir/us/core/STU7/StructureDefinition-us-core-ethnicity.html">US Core

apps/bfd-server-ng/src/test/java/gov/cms/bfd/server/ng/EobValidityIT.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ private void validateEob(ExplanationOfBenefit eob) {
2828
assertTrue(eob.hasStatus(), "EOB should have status");
2929
assertTrue(eob.hasCreated(), "EOB should have created");
3030
assertTrue(eob.hasUse(), "EOB should have use");
31+
assertTrue(
32+
eob.hasProvider(),
33+
"EOB should have provider, or data-absent-reason when provider/org npi is not provided");
3134
assertFalse(
3235
eob.getMeta().getProfile().isEmpty(), "EOB Meta must have at least one Profile defined");
3336
assertFalse(eob.hasExtension());

apps/bfd-server-ng/src/test/java/gov/cms/bfd/server/ng/__snapshots__/EobSamhsaFilterIT.snap

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3928,6 +3928,12 @@ gov.cms.bfd.server.ng.EobSamhsaFilterIT.samhsaClaimsIncludeSecurityTagsWhenAllow
39283928
} ]
39293929
} ]
39303930
} ],
3931+
"provider" : {
3932+
"extension" : [ {
3933+
"url" : "http://hl7.org/fhir/StructureDefinition/data-absent-reason",
3934+
"valueCode" : "unknown"
3935+
} ]
3936+
},
39313937
"resourceType" : "ExplanationOfBenefit",
39323938
"status" : "active",
39333939
"subType" : {
@@ -11252,6 +11258,12 @@ gov.cms.bfd.server.ng.EobSamhsaFilterIT.shouldFilterSamhsaNoCert[412457726]=[
1125211258
"value" : 254072.03
1125311259
}
1125411260
},
11261+
"provider" : {
11262+
"extension" : [ {
11263+
"url" : "http://hl7.org/fhir/StructureDefinition/data-absent-reason",
11264+
"valueCode" : "unknown"
11265+
} ]
11266+
},
1125511267
"resourceType" : "ExplanationOfBenefit",
1125611268
"status" : "active",
1125711269
"subType" : {
@@ -13230,6 +13242,12 @@ gov.cms.bfd.server.ng.EobSamhsaFilterIT.shouldFilterSamhsaNoCert[412457726]=[
1323013242
"value" : 2690.19
1323113243
}
1323213244
},
13245+
"provider" : {
13246+
"extension" : [ {
13247+
"url" : "http://hl7.org/fhir/StructureDefinition/data-absent-reason",
13248+
"valueCode" : "unknown"
13249+
} ]
13250+
},
1323313251
"resourceType" : "ExplanationOfBenefit",
1323413252
"status" : "active",
1323513253
"subType" : {
@@ -20896,6 +20914,12 @@ gov.cms.bfd.server.ng.EobSamhsaFilterIT.shouldFilterSamhsaSamhsaNotAllowedCert[4
2089620914
"value" : 254072.03
2089720915
}
2089820916
},
20917+
"provider" : {
20918+
"extension" : [ {
20919+
"url" : "http://hl7.org/fhir/StructureDefinition/data-absent-reason",
20920+
"valueCode" : "unknown"
20921+
} ]
20922+
},
2089920923
"resourceType" : "ExplanationOfBenefit",
2090020924
"status" : "active",
2090120925
"subType" : {
@@ -22874,6 +22898,12 @@ gov.cms.bfd.server.ng.EobSamhsaFilterIT.shouldFilterSamhsaSamhsaNotAllowedCert[4
2287422898
"value" : 2690.19
2287522899
}
2287622900
},
22901+
"provider" : {
22902+
"extension" : [ {
22903+
"url" : "http://hl7.org/fhir/StructureDefinition/data-absent-reason",
22904+
"valueCode" : "unknown"
22905+
} ]
22906+
},
2287722907
"resourceType" : "ExplanationOfBenefit",
2287822908
"status" : "active",
2287922909
"subType" : {

0 commit comments

Comments
 (0)