use of org.hl7.fhir.r4.model.ExplanationOfBenefit.Use in project beneficiary-fhir-data by CMSgov.
the class ExplanationOfBenefitResourceProvider method findByPatient.
/**
* Adds support for the FHIR "search" operation for {@link ExplanationOfBenefit}s, allowing users
* to search by {@link ExplanationOfBenefit#getPatient()}.
*
* <p>The {@link Search} annotation indicates that this method supports the search operation.
* There may be many different methods annotated with this {@link Search} annotation, to support
* many different search criteria.
*
* @param patient a {@link ReferenceParam} for the {@link ExplanationOfBenefit#getPatient()} to
* try and find matches for {@link ExplanationOfBenefit}s
* @param type a list of {@link ClaimType} to include in the result. Defaults to all types.
* @param startIndex an {@link OptionalParam} for the startIndex (or offset) used to determine
* pagination
* @param excludeSamhsa an {@link OptionalParam} that, if <code>"true"</code>, will use {@link
* Stu3EobSamhsaMatcher} to filter out all SAMHSA-related claims from the results
* @param lastUpdated an {@link OptionalParam} that specifies a date range for the lastUpdated
* field.
* @param serviceDate an {@link OptionalParam} that specifies a date range for {@link
* ExplanationOfBenefit}s that completed
* @param requestDetails a {@link RequestDetails} containing the details of the request URL, used
* to parse out pagination values
* @return Returns a {@link Bundle} of {@link ExplanationOfBenefit}s, which may contain multiple
* matching resources, or may also be empty.
*/
@Search
@Trace
public Bundle findByPatient(@RequiredParam(name = ExplanationOfBenefit.SP_PATIENT) @Description(shortDefinition = "The patient identifier to search for") ReferenceParam patient, @OptionalParam(name = "type") @Description(shortDefinition = "A list of claim types to include") TokenAndListParam type, @OptionalParam(name = "startIndex") @Description(shortDefinition = "The offset used for result pagination") String startIndex, @OptionalParam(name = "excludeSAMHSA") @Description(shortDefinition = "If true, exclude all SAMHSA-related resources") String excludeSamhsa, @OptionalParam(name = "_lastUpdated") @Description(shortDefinition = "Include resources last updated in the given range") DateRangeParam lastUpdated, @OptionalParam(name = "service-date") @Description(shortDefinition = "Include resources that completed in the given range") DateRangeParam serviceDate, RequestDetails requestDetails) {
/*
* startIndex is an optional parameter here because it must be declared in the
* event it is passed in. However, it is not being used here because it is also
* contained within requestDetails and parsed out along with other parameters
* later.
*/
String beneficiaryId = patient.getIdPart();
Set<ClaimType> claimTypes = parseTypeParam(type);
Boolean includeTaxNumbers = returnIncludeTaxNumbers(requestDetails);
OffsetLinkBuilder paging = new OffsetLinkBuilder(requestDetails, "/ExplanationOfBenefit?");
Operation operation = new Operation(Operation.Endpoint.V1_EOB);
operation.setOption("by", "patient");
operation.setOption("types", (claimTypes.size() == ClaimType.values().length) ? "*" : claimTypes.stream().sorted(Comparator.comparing(ClaimType::name)).collect(Collectors.toList()).toString());
operation.setOption("IncludeTaxNumbers", "" + includeTaxNumbers);
operation.setOption("pageSize", paging.isPagingRequested() ? "" + paging.getPageSize() : "*");
operation.setOption("_lastUpdated", Boolean.toString(lastUpdated != null && !lastUpdated.isEmpty()));
operation.setOption("service-date", Boolean.toString(serviceDate != null && !serviceDate.isEmpty()));
operation.publishOperationName();
List<IBaseResource> eobs = new ArrayList<IBaseResource>();
// Optimize when the lastUpdated parameter is specified and result set is empty
if (loadedFilterManager.isResultSetEmpty(beneficiaryId, lastUpdated)) {
return TransformerUtils.createBundle(paging, eobs, loadedFilterManager.getTransactionTime());
}
/*
* The way our JPA/SQL schema is setup, we have to run a separate search for
* each claim type, then combine the results. It's not super efficient, but it's
* also not so inefficient that it's worth fixing.
*/
if (claimTypes.contains(ClaimType.CARRIER))
eobs.addAll(transformToEobs(ClaimType.CARRIER, findClaimTypeByPatient(ClaimType.CARRIER, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (claimTypes.contains(ClaimType.DME))
eobs.addAll(transformToEobs(ClaimType.DME, findClaimTypeByPatient(ClaimType.DME, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (claimTypes.contains(ClaimType.HHA))
eobs.addAll(transformToEobs(ClaimType.HHA, findClaimTypeByPatient(ClaimType.HHA, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (claimTypes.contains(ClaimType.HOSPICE))
eobs.addAll(transformToEobs(ClaimType.HOSPICE, findClaimTypeByPatient(ClaimType.HOSPICE, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (claimTypes.contains(ClaimType.INPATIENT))
eobs.addAll(transformToEobs(ClaimType.INPATIENT, findClaimTypeByPatient(ClaimType.INPATIENT, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (claimTypes.contains(ClaimType.OUTPATIENT))
eobs.addAll(transformToEobs(ClaimType.OUTPATIENT, findClaimTypeByPatient(ClaimType.OUTPATIENT, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (claimTypes.contains(ClaimType.PDE))
eobs.addAll(transformToEobs(ClaimType.PDE, findClaimTypeByPatient(ClaimType.PDE, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (claimTypes.contains(ClaimType.SNF))
eobs.addAll(transformToEobs(ClaimType.SNF, findClaimTypeByPatient(ClaimType.SNF, beneficiaryId, lastUpdated, serviceDate), Optional.of(includeTaxNumbers)));
if (Boolean.parseBoolean(excludeSamhsa))
filterSamhsa(eobs);
eobs.sort(ExplanationOfBenefitResourceProvider::compareByClaimIdThenClaimType);
// Add bene_id to MDC logs
TransformerUtils.logBeneIdToMdc(Arrays.asList(beneficiaryId));
return TransformerUtils.createBundle(paging, eobs, loadedFilterManager.getTransactionTime());
}
use of org.hl7.fhir.r4.model.ExplanationOfBenefit.Use in project beneficiary-fhir-data by CMSgov.
the class ExplanationOfBenefitResourceProvider method findClaimTypeByPatient.
/**
* @param claimType the {@link ClaimType} to find
* @param patientId the {@link Beneficiary#getBeneficiaryId()} to filter by
* @param lastUpdated the update time to filter by
* @return the matching claim/event entities
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Trace
private <T> List<T> findClaimTypeByPatient(ClaimType claimType, String patientId, DateRangeParam lastUpdated, DateRangeParam serviceDate) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteria = builder.createQuery((Class) claimType.getEntityClass());
Root root = criteria.from(claimType.getEntityClass());
claimType.getEntityLazyAttributes().stream().forEach(a -> root.fetch(a));
criteria.select(root).distinct(true);
// Search for a beneficiary's records. Use lastUpdated if present
Predicate wherePredicate = builder.equal(root.get(claimType.getEntityBeneficiaryIdAttribute()), patientId);
if (lastUpdated != null && !lastUpdated.isEmpty()) {
Predicate predicate = QueryUtils.createLastUpdatedPredicate(builder, root, lastUpdated);
wherePredicate = builder.and(wherePredicate, predicate);
}
criteria.where(wherePredicate);
List<T> claimEntities = null;
Long eobsByBeneIdQueryNanoSeconds = null;
Timer.Context timerEobQuery = metricRegistry.timer(MetricRegistry.name(metricRegistry.getClass().getSimpleName(), "query", "eobs_by_bene_id", claimType.name().toLowerCase())).time();
try {
claimEntities = entityManager.createQuery(criteria).getResultList();
} finally {
eobsByBeneIdQueryNanoSeconds = timerEobQuery.stop();
TransformerUtils.recordQueryInMdc(String.format("eobs_by_bene_id.%s", claimType.name().toLowerCase()), eobsByBeneIdQueryNanoSeconds, claimEntities == null ? 0 : claimEntities.size());
}
if (claimEntities != null && serviceDate != null && !serviceDate.isEmpty()) {
final Instant lowerBound = serviceDate.getLowerBoundAsInstant() != null ? serviceDate.getLowerBoundAsInstant().toInstant() : null;
final Instant upperBound = serviceDate.getUpperBoundAsInstant() != null ? serviceDate.getUpperBoundAsInstant().toInstant() : null;
final java.util.function.Predicate<LocalDate> lowerBoundCheck = lowerBound == null ? (date) -> true : (date) -> compareLocalDate(date, lowerBound.atZone(ZoneId.systemDefault()).toLocalDate(), serviceDate.getLowerBound().getPrefix());
final java.util.function.Predicate<LocalDate> upperBoundCheck = upperBound == null ? (date) -> true : (date) -> compareLocalDate(date, upperBound.atZone(ZoneId.systemDefault()).toLocalDate(), serviceDate.getUpperBound().getPrefix());
return claimEntities.stream().filter(entity -> lowerBoundCheck.test(claimType.getServiceEndAttributeFunction().apply(entity)) && upperBoundCheck.test(claimType.getServiceEndAttributeFunction().apply(entity))).collect(Collectors.toList());
}
return claimEntities;
}
use of org.hl7.fhir.r4.model.ExplanationOfBenefit.Use in project beneficiary-fhir-data by CMSgov.
the class HospiceClaimTransformer method transform.
/**
* @param metricRegistry the {@link MetricRegistry} to use
* @param claim the CCW {@link HospiceClaim} to transform
* @param includeTaxNumbers whether or not to include tax numbers in the result (see {@link
* ExplanationOfBenefitResourceProvider#HEADER_NAME_INCLUDE_TAX_NUMBERS}, defaults to <code>
* false</code>)
* @return a FHIR {@link ExplanationOfBenefit} resource that represents the specified {@link
* HospiceClaim}
*/
@Trace
static ExplanationOfBenefit transform(MetricRegistry metricRegistry, Object claim, Optional<Boolean> includeTaxNumbers) {
Timer.Context timer = metricRegistry.timer(MetricRegistry.name(HospiceClaimTransformer.class.getSimpleName(), "transform")).time();
if (!(claim instanceof HospiceClaim))
throw new BadCodeMonkeyException();
ExplanationOfBenefit eob = transformClaim((HospiceClaim) claim);
timer.stop();
return eob;
}
use of org.hl7.fhir.r4.model.ExplanationOfBenefit.Use in project beneficiary-fhir-data by CMSgov.
the class InpatientClaimTransformer method transform.
/**
* @param metricRegistry the {@link MetricRegistry} to use
* @param claim the CCW {@link InpatientClaim} to transform
* @param includeTaxNumbers whether or not to include tax numbers in the result (see {@link
* ExplanationOfBenefitResourceProvider#HEADER_NAME_INCLUDE_TAX_NUMBERS}, defaults to <code>
* false</code>)
* @return a FHIR {@link ExplanationOfBenefit} resource that represents the specified {@link
* InpatientClaim}
*/
@Trace
static ExplanationOfBenefit transform(MetricRegistry metricRegistry, Object claim, Optional<Boolean> includeTaxNumbers) {
Timer.Context timer = metricRegistry.timer(MetricRegistry.name(InpatientClaimTransformer.class.getSimpleName(), "transform")).time();
if (!(claim instanceof InpatientClaim))
throw new BadCodeMonkeyException();
ExplanationOfBenefit eob = transformClaim((InpatientClaim) claim);
timer.stop();
return eob;
}
use of org.hl7.fhir.r4.model.ExplanationOfBenefit.Use in project beneficiary-fhir-data by CMSgov.
the class TransformerUtilsV2 method createExtensionQuantity.
/**
* @param ccwVariable the {@link CcwCodebookInterface} being mapped
* @param quantityValue the value to use for {@link Coding#getCode()} for the resulting {@link
* Coding}
* @return the output {@link Extension}, with {@link Extension#getValue()} set to represent the
* specified input values
*/
static Extension createExtensionQuantity(CcwCodebookInterface ccwVariable, Optional<? extends Number> quantityValue) {
if (!quantityValue.isPresent()) {
throw new IllegalArgumentException();
}
Quantity quantity;
if (quantityValue.get() instanceof BigDecimal) {
quantity = new Quantity().setValue((BigDecimal) quantityValue.get());
} else {
throw new BadCodeMonkeyException();
}
String extensionUrl = CCWUtils.calculateVariableReferenceUrl(ccwVariable);
Extension extension = new Extension(extensionUrl, quantity);
return extension;
}
Aggregations