use of org.hl7.fhir.r5.model.Patient in project beneficiary-fhir-data by CMSgov.
the class R4CoverageResourceProvider method searchByBeneficiary.
/**
* Adds support for the FHIR "search" operation for {@link Coverage}s, allowing users to search by
* {@link Coverage#getBeneficiary()}.
*
* <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 beneficiary a {@link ReferenceParam} for the {@link Coverage#getBeneficiary()} to try
* and find matches for
* @param startIndex an {@link OptionalParam} for the startIndex (or offset) used to determine
* pagination
* @param lastUpdated an {@link OptionalParam} to filter the results based on the passed date
* range
* @param requestDetails a {@link RequestDetails} containing the details of the request URL, used
* to parse out pagination values
* @return Returns a {@link List} of {@link Coverage}s, which may contain multiple matching
* resources, or may also be empty.
*/
@Search
@Trace
public Bundle searchByBeneficiary(@RequiredParam(name = Coverage.SP_BENEFICIARY) @Description(shortDefinition = "The patient identifier to search for") ReferenceParam beneficiary, @OptionalParam(name = "startIndex") @Description(shortDefinition = "The offset used for result pagination") String startIndex, @OptionalParam(name = "_lastUpdated") @Description(shortDefinition = "Include resources last updated in the given range") DateRangeParam lastUpdated, RequestDetails requestDetails) {
List<IBaseResource> coverages;
try {
Beneficiary beneficiaryEntity = findBeneficiaryById(beneficiary.getIdPart(), lastUpdated);
if (!beneficiaryEntity.getBeneEnrollmentReferenceYear().isPresent()) {
throw new ResourceNotFoundException("Cannot find coverage for non present enrollment year");
}
coverages = CoverageTransformerV2.transform(metricRegistry, beneficiaryEntity);
} catch (NoResultException e) {
coverages = new LinkedList<IBaseResource>();
}
OffsetLinkBuilder paging = new OffsetLinkBuilder(requestDetails, "/Coverage?");
Operation operation = new Operation(Operation.Endpoint.V2_COVERAGE);
operation.setOption("by", "beneficiary");
operation.setOption("pageSize", paging.isPagingRequested() ? "" + paging.getPageSize() : "*");
operation.setOption("_lastUpdated", Boolean.toString(lastUpdated != null && !lastUpdated.isEmpty()));
operation.publishOperationName();
// Add bene_id to MDC logs
TransformerUtilsV2.logBeneIdToMdc(Arrays.asList(beneficiary.getIdPart()));
return TransformerUtilsV2.createBundle(paging, coverages, loadedFilterManager.getTransactionTime());
}
use of org.hl7.fhir.r5.model.Patient in project beneficiary-fhir-data by CMSgov.
the class R4PatientResourceProvider method searchByIdentifier.
/**
* Adds support for the FHIR "search" operation for {@link Patient}s, allowing users to search by
* {@link Patient#getIdentifier()}. Specifically, the following criteria are supported:
*
* <p>Searches that don't match one of the above forms are not supported.
*
* <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 identifier an {@link Identifier} {@link TokenParam} for the {@link
* Patient#getIdentifier()} to try and find a matching {@link Patient} for
* @param startIndex an {@link OptionalParam} for the startIndex (or offset) used to determine
* pagination
* @param lastUpdated an {@link OptionalParam} to filter the results based on the passed date
* range
* @param requestDetails a {@link RequestDetails} containing the details of the request URL, used
* to parse out pagination values
* @return Returns a {@link List} of {@link Patient}s, which may contain multiple matching
* resources, or may also be empty.
*/
@Search
@Trace
public Bundle searchByIdentifier(@RequiredParam(name = Patient.SP_IDENTIFIER) @Description(shortDefinition = "The patient identifier to search for") TokenParam identifier, @OptionalParam(name = "startIndex") @Description(shortDefinition = "The offset used for result pagination") String startIndex, @OptionalParam(name = "_lastUpdated") @Description(shortDefinition = "Include resources last updated in the given range") DateRangeParam lastUpdated, RequestDetails requestDetails) {
if (identifier.getQueryParameterQualifier() != null) {
throw new InvalidRequestException("Unsupported query parameter qualifier: " + identifier.getQueryParameterQualifier());
}
if (!SUPPORTED_HASH_IDENTIFIER_SYSTEMS.contains(identifier.getSystem()))
throw new InvalidRequestException("Unsupported identifier system: " + identifier.getSystem());
RequestHeaders requestHeader = RequestHeaders.getHeaderWrapper(requestDetails);
Operation operation = new Operation(Operation.Endpoint.V2_PATIENT);
operation.setOption("by", "identifier");
requestHeader.getNVPairs().forEach((n, v) -> operation.setOption(n, v.toString()));
operation.setOption("_lastUpdated", Boolean.toString(lastUpdated != null && !lastUpdated.isEmpty()));
operation.publishOperationName();
List<IBaseResource> patients;
try {
Patient patient;
switch(identifier.getSystem()) {
case TransformerConstants.CODING_BBAPI_BENE_MBI_HASH:
patient = queryDatabaseByMbiHash(identifier.getValue(), requestHeader);
break;
case TransformerConstants.CODING_BBAPI_BENE_HICN_HASH:
case TransformerConstants.CODING_BBAPI_BENE_HICN_HASH_OLD:
patient = queryDatabaseByHicnHash(identifier.getValue(), requestHeader);
break;
default:
throw new InvalidRequestException("Unsupported identifier system: " + identifier.getSystem());
}
patients = QueryUtils.isInRange(patient.getMeta().getLastUpdated().toInstant(), lastUpdated) ? Collections.singletonList(patient) : Collections.emptyList();
} catch (NoResultException e) {
patients = new LinkedList<>();
}
OffsetLinkBuilder paging = new OffsetLinkBuilder(requestDetails, "/Patient?");
return TransformerUtilsV2.createBundle(paging, patients, loadedFilterManager.getTransactionTime());
}
use of org.hl7.fhir.r5.model.Patient in project beneficiary-fhir-data by CMSgov.
the class R4PatientResourceProvider method searchByLogicalId.
/**
* Adds support for the FHIR "search" operation for {@link Patient}s, allowing users to search by
* {@link Patient#getId()}.
*
* <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 logicalId a {@link TokenParam} (with no system, per the spec) for the {@link
* Patient#getId()} to try and find a matching {@link Patient} for
* @param startIndex an {@link OptionalParam} for the startIndex (or offset) used to determine
* pagination
* @param lastUpdated an {@link OptionalParam} to filter the results based on the passed date
* range
* @param requestDetails a {@link RequestDetails} containing the details of the request URL, used
* to parse out pagination values
* @return Returns a {@link List} of {@link Patient}s, which may contain multiple matching
* resources, or may also be empty.
*/
@Search
@Trace
public Bundle searchByLogicalId(@RequiredParam(name = Patient.SP_RES_ID) @Description(shortDefinition = "The patient identifier to search for") TokenParam logicalId, @OptionalParam(name = "startIndex") @Description(shortDefinition = "The offset used for result pagination") String startIndex, @OptionalParam(name = "_lastUpdated") @Description(shortDefinition = "Include resources last updated in the given range") DateRangeParam lastUpdated, RequestDetails requestDetails) {
if (logicalId.getQueryParameterQualifier() != null)
throw new InvalidRequestException("Unsupported query parameter qualifier: " + logicalId.getQueryParameterQualifier());
if (logicalId.getSystem() != null && !logicalId.getSystem().isEmpty())
throw new InvalidRequestException("Unsupported query parameter system: " + logicalId.getSystem());
if (logicalId.getValueNotNull().isEmpty())
throw new InvalidRequestException("Unsupported query parameter value: " + logicalId.getValue());
List<IBaseResource> patients;
if (loadedFilterManager.isResultSetEmpty(logicalId.getValue(), lastUpdated)) {
patients = Collections.emptyList();
} else {
try {
patients = Optional.of(read(new IdType(logicalId.getValue()), requestDetails)).filter(p -> QueryUtils.isInRange(p.getMeta().getLastUpdated().toInstant(), lastUpdated)).map(p -> Collections.singletonList((IBaseResource) p)).orElse(Collections.emptyList());
} catch (ResourceNotFoundException e) {
patients = Collections.emptyList();
}
}
/*
* Publish the operation name. Note: This is a bit later than we'd normally do this, as we need
* to override the operation name that was published by the possible call to read(...), above.
*/
RequestHeaders requestHeader = RequestHeaders.getHeaderWrapper(requestDetails);
Operation operation = new Operation(Operation.Endpoint.V2_PATIENT);
operation.setOption("by", "id");
// track all api hdrs
requestHeader.getNVPairs().forEach((n, v) -> operation.setOption(n, v.toString()));
operation.setOption("_lastUpdated", Boolean.toString(lastUpdated != null && !lastUpdated.isEmpty()));
operation.publishOperationName();
OffsetLinkBuilder paging = new OffsetLinkBuilder(requestDetails, "/Patient?");
Bundle bundle = TransformerUtilsV2.createBundle(paging, patients, loadedFilterManager.getTransactionTime());
return bundle;
}
use of org.hl7.fhir.r5.model.Patient in project beneficiary-fhir-data by CMSgov.
the class TransformerUtilsV2 method addResourcesToBundle.
/**
* @param bundle a {@link Bundle} to add the list of {@link ExplanationOfBenefit} resources to.
* @param resources a list of either {@link ExplanationOfBenefit}s, {@link Coverage}s, or {@link
* Patient}s, of which a portion will be added to the bundle based on the paging values
* @return Returns a {@link Bundle} of {@link ExplanationOfBenefit}s, {@link Coverage}s, or {@link
* Patient}s, which may contain multiple matching resources, or may also be empty.
*/
public static Bundle addResourcesToBundle(Bundle bundle, List<IBaseResource> resources) {
Set<String> beneIds = new HashSet<String>();
for (IBaseResource res : resources) {
BundleEntryComponent entry = bundle.addEntry();
entry.setResource((Resource) res);
if (entry.getResource().getResourceType() == ResourceType.ExplanationOfBenefit) {
ExplanationOfBenefit eob = ((ExplanationOfBenefit) entry.getResource());
if (eob != null && eob.getPatient() != null && !Strings.isNullOrEmpty(eob.getPatient().getReference())) {
String reference = eob.getPatient().getReference().replace("Patient/", "");
if (!Strings.isNullOrEmpty(reference)) {
beneIds.add(reference);
}
}
} else if (entry.getResource().getResourceType() == ResourceType.Patient) {
Patient patient = ((Patient) entry.getResource());
if (patient != null && !Strings.isNullOrEmpty(patient.getId())) {
beneIds.add(patient.getId());
}
} else if (entry.getResource().getResourceType() == ResourceType.Coverage) {
Coverage coverage = ((Coverage) entry.getResource());
if (coverage != null && coverage.getBeneficiary() != null && !Strings.isNullOrEmpty(coverage.getBeneficiary().getReference())) {
String reference = coverage.getBeneficiary().getReference().replace("Patient/", "");
if (!Strings.isNullOrEmpty(reference)) {
beneIds.add(reference);
}
}
}
}
logBeneIdToMdc(beneIds);
return bundle;
}
use of org.hl7.fhir.r5.model.Patient in project beneficiary-fhir-data by CMSgov.
the class BeneficiaryTransformerV2 method transform.
/**
* @param beneficiary the CCW {@link Beneficiary} to transform
* @param requestHeader {@link RequestHeaders} the holder that contains all supported resource
* request headers
* @return a FHIR {@link Patient} resource that represents the specified {@link Beneficiary}
*/
private static Patient transform(Beneficiary beneficiary, RequestHeaders requestHeader) {
Objects.requireNonNull(beneficiary);
Patient patient = new Patient();
/*
* Notify end users when they receive Patient records impacted by
* https://jira.cms.gov/browse/BFD-1566. See the documentation on
* LoadAppOptions.isFilteringNonNullAndNon2022Benes() for details.
*/
if (!beneficiary.getSkippedRifRecords().isEmpty()) {
patient.getMeta().addTag(TransformerConstants.CODING_SYSTEM_BFD_TAGS, TransformerConstants.CODING_BFD_TAGS_DELAYED_BACKDATED_ENROLLMENT, TransformerConstants.CODING_BFD_TAGS_DELAYED_BACKDATED_ENROLLMENT_DISPLAY);
}
// Required values not directly mapped
patient.getMeta().addProfile(ProfileConstants.C4BB_PATIENT_URL);
patient.setId(beneficiary.getBeneficiaryId());
// BENE_ID => patient.identifier
TransformerUtilsV2.addIdentifierSlice(patient, TransformerUtilsV2.createCodeableConcept(TransformerConstants.CODING_SYSTEM_HL7_IDENTIFIER_TYPE, null, TransformerConstants.PATIENT_MB_ID_DISPLAY, "MB"), Optional.of(beneficiary.getBeneficiaryId()), Optional.of(TransformerConstants.CODING_BBAPI_BENE_ID));
// Unhashed MBI
if (beneficiary.getMedicareBeneficiaryId().isPresent()) {
Period mbiPeriod = new Period();
if (beneficiary.getMbiEffectiveDate().isPresent()) {
TransformerUtilsV2.setPeriodStart(mbiPeriod, beneficiary.getMbiEffectiveDate().get());
}
if (beneficiary.getMbiObsoleteDate().isPresent()) {
TransformerUtilsV2.setPeriodEnd(mbiPeriod, beneficiary.getMbiObsoleteDate().get());
}
addUnhashedIdentifier(patient, beneficiary.getMedicareBeneficiaryId().get(), TransformerConstants.CODING_BBAPI_MEDICARE_BENEFICIARY_ID_UNHASHED, TransformerUtilsV2.createIdentifierCurrencyExtension(CurrencyIdentifier.CURRENT), mbiPeriod);
}
// Add lastUpdated
TransformerUtilsV2.setLastUpdated(patient, beneficiary.getLastUpdated());
/**
* The following logic attempts to distill {@link MedicareBeneficiaryIdHistory} data into only
* those records which have an endDate present. This is due to the fact that it includes the
* CURRENT MBI record which was handle previously. Also, the {@link
* MedicareBeneficiaryIdHistory} table appears to contain spurious records with the only
* difference is the generated surrogate key identifier.
*/
if (requestHeader.isMBIinIncludeIdentifiers()) {
HashMap<LocalDate, MedicareBeneficiaryIdHistory> mbiHistMap = new HashMap<LocalDate, MedicareBeneficiaryIdHistory>();
for (MedicareBeneficiaryIdHistory mbiHistory : beneficiary.getMedicareBeneficiaryIdHistories()) {
// and will have been previously provided as the CURRENT rcd.
if (mbiHistory.getMbiEndDate().isPresent()) {
mbiHistMap.put(mbiHistory.getMbiEndDate().get(), mbiHistory);
}
// would come in ascending order, so any rcd would have a later
// update date than prev rcd.
TransformerUtilsV2.updateMaxLastUpdated(patient, mbiHistory.getLastUpdated());
}
if (mbiHistMap.size() > 0) {
Extension historicalIdentifier = TransformerUtilsV2.createIdentifierCurrencyExtension(CurrencyIdentifier.HISTORIC);
for (MedicareBeneficiaryIdHistory mbi : mbiHistMap.values()) {
addUnhashedIdentifier(patient, mbi.getMedicareBeneficiaryId().get(), TransformerConstants.CODING_BBAPI_MEDICARE_BENEFICIARY_ID_UNHASHED, historicalIdentifier, null);
}
}
}
// support header includeAddressFields from downstream components e.g. BB2
// per requirement of BFD-379, BB2 always send header includeAddressFields = False
Boolean addrHdrVal = requestHeader.getValue(R4PatientResourceProvider.HEADER_NAME_INCLUDE_ADDRESS_FIELDS);
if (addrHdrVal != null && addrHdrVal) {
patient.addAddress().setState(beneficiary.getStateCode()).setPostalCode(beneficiary.getPostalCode()).setCity(beneficiary.getDerivedCityName().orElse(null)).addLine(beneficiary.getDerivedMailingAddress1().orElse(null)).addLine(beneficiary.getDerivedMailingAddress2().orElse(null)).addLine(beneficiary.getDerivedMailingAddress3().orElse(null)).addLine(beneficiary.getDerivedMailingAddress4().orElse(null)).addLine(beneficiary.getDerivedMailingAddress5().orElse(null)).addLine(beneficiary.getDerivedMailingAddress6().orElse(null));
} else {
patient.addAddress().setState(beneficiary.getStateCode()).setPostalCode(beneficiary.getPostalCode());
}
if (beneficiary.getBirthDate() != null) {
patient.setBirthDate(TransformerUtilsV2.convertToDate(beneficiary.getBirthDate()));
}
// "Patient.deceased[x]": ["boolean", "dateTime"],
if (beneficiary.getBeneficiaryDateOfDeath().isPresent()) {
patient.setDeceased(new DateTimeType(TransformerUtilsV2.convertToDate(beneficiary.getBeneficiaryDateOfDeath().get()), TemporalPrecisionEnum.DAY));
} else {
patient.setDeceased(new BooleanType(false));
}
char sex = beneficiary.getSex();
if (sex == Sex.MALE.getCode())
patient.setGender((AdministrativeGender.MALE));
else if (sex == Sex.FEMALE.getCode())
patient.setGender((AdministrativeGender.FEMALE));
else
patient.setGender((AdministrativeGender.UNKNOWN));
if (beneficiary.getRace().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.RACE, beneficiary.getRace().get()));
// for race category, v2 will just treat all race codes as Unknown (UNK);
// thus we'll simply pass in the Unknown race code .
RaceCategory raceCategory = TransformerUtilsV2.getRaceCategory('0');
Extension raceChildOMBExt1 = new Extension().setValue(new Coding().setCode(raceCategory.toCode()).setSystem(raceCategory.getSystem()).setDisplay(raceCategory.getDisplay())).setUrl("ombCategory");
Extension raceChildOMBExt2 = new Extension().setValue(new StringType().setValue(raceCategory.getDisplay())).setUrl("text");
Extension parentOMBRace = new Extension().setUrl(TransformerConstants.CODING_RACE_US);
parentOMBRace.addExtension(raceChildOMBExt1);
parentOMBRace.addExtension(raceChildOMBExt2);
patient.addExtension(parentOMBRace);
}
HumanName name = patient.addName().addGiven(beneficiary.getNameGiven()).setFamily(beneficiary.getNameSurname()).setUse(HumanName.NameUse.USUAL);
if (beneficiary.getNameMiddleInitial().isPresent()) {
name.addGiven(String.valueOf(beneficiary.getNameMiddleInitial().get()));
}
// The reference year of the enrollment data
if (beneficiary.getBeneEnrollmentReferenceYear().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionDate(CcwCodebookVariable.RFRNC_YR, beneficiary.getBeneEnrollmentReferenceYear()));
}
// Monthly Medicare-Medicaid dual eligibility codes
if (beneficiary.getMedicaidDualEligibilityJanCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_01, beneficiary.getMedicaidDualEligibilityJanCode()));
}
if (beneficiary.getMedicaidDualEligibilityFebCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_02, beneficiary.getMedicaidDualEligibilityFebCode()));
}
if (beneficiary.getMedicaidDualEligibilityMarCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_03, beneficiary.getMedicaidDualEligibilityMarCode()));
}
if (beneficiary.getMedicaidDualEligibilityAprCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_04, beneficiary.getMedicaidDualEligibilityAprCode()));
}
if (beneficiary.getMedicaidDualEligibilityMayCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_05, beneficiary.getMedicaidDualEligibilityMayCode()));
}
if (beneficiary.getMedicaidDualEligibilityJunCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_06, beneficiary.getMedicaidDualEligibilityJunCode()));
}
if (beneficiary.getMedicaidDualEligibilityJulCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_07, beneficiary.getMedicaidDualEligibilityJulCode()));
}
if (beneficiary.getMedicaidDualEligibilityAugCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_08, beneficiary.getMedicaidDualEligibilityAugCode()));
}
if (beneficiary.getMedicaidDualEligibilitySeptCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_09, beneficiary.getMedicaidDualEligibilitySeptCode()));
}
if (beneficiary.getMedicaidDualEligibilityOctCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_10, beneficiary.getMedicaidDualEligibilityOctCode()));
}
if (beneficiary.getMedicaidDualEligibilityNovCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_11, beneficiary.getMedicaidDualEligibilityNovCode()));
}
if (beneficiary.getMedicaidDualEligibilityDecCode().isPresent()) {
patient.addExtension(TransformerUtilsV2.createExtensionCoding(patient, CcwCodebookVariable.DUAL_12, beneficiary.getMedicaidDualEligibilityDecCode()));
}
// Last Updated => Patient.meta.lastUpdated
TransformerUtilsV2.setLastUpdated(patient, beneficiary.getLastUpdated());
return patient;
}
Aggregations