Search in sources :

Example 6 with RecordAction

use of gov.cms.bfd.model.rif.RecordAction in project beneficiary-fhir-data by CMSgov.

the class RifFilesProcessor method buildHospiceClaimEvent.

/**
 * @param fileEvent the {@link RifFileEvent} being processed
 * @param csvRecords the {@link CSVRecord}s to be mapped, which must be from a {@link
 *     RifFileType#HOSPICE} {@link RifFile}
 * @return a {@link RifRecordEvent} built from the specified {@link CSVRecord}s
 */
private static RifRecordEvent<HospiceClaim> buildHospiceClaimEvent(RifFileEvent fileEvent, List<CSVRecord> csvRecords) {
    if (LOGGER.isTraceEnabled())
        LOGGER.trace(csvRecords.toString());
    CSVRecord firstCsvRecord = csvRecords.get(0);
    RecordAction recordAction = RecordAction.match(firstCsvRecord.get("DML_IND"));
    HospiceClaim claim = HospiceClaimParser.parseRif(csvRecords);
    return new RifRecordEvent<HospiceClaim>(fileEvent, csvRecords, recordAction, claim.getBeneficiaryId(), claim);
}
Also used : RifRecordEvent(gov.cms.bfd.model.rif.RifRecordEvent) CSVRecord(org.apache.commons.csv.CSVRecord) RecordAction(gov.cms.bfd.model.rif.RecordAction) HospiceClaim(gov.cms.bfd.model.rif.HospiceClaim)

Example 7 with RecordAction

use of gov.cms.bfd.model.rif.RecordAction in project beneficiary-fhir-data by CMSgov.

the class RifLoader method process.

/**
 * @param recordsBatch the {@link RifRecordEvent}s to process
 * @param loadedFileBuilder the builder for the {@LoadedFile} associated with this batch
 * @param postgresBatch the {@link PostgreSqlCopyInserter} for the current set of {@link
 *     RifFilesEvent}s being processed
 * @return the {@link RifRecordLoadResult}s that model the results of the operation
 */
private List<RifRecordLoadResult> process(List<RifRecordEvent<?>> recordsBatch, long loadedFileId, PostgreSqlCopyInserter postgresBatch) {
    RifFileEvent fileEvent = recordsBatch.get(0).getFileEvent();
    MetricRegistry fileEventMetrics = fileEvent.getEventMetrics();
    RifFileType rifFileType = fileEvent.getFile().getFileType();
    if (rifFileType == RifFileType.BENEFICIARY_HISTORY) {
        for (RifRecordEvent<?> rifRecordEvent : recordsBatch) {
            hashBeneficiaryHistoryHicn(rifRecordEvent);
            hashBeneficiaryHistoryMbi(rifRecordEvent);
        }
    }
    // Only one of each failure/success Timer.Contexts will be applied.
    Timer.Context timerBatchSuccess = appState.getMetrics().timer(MetricRegistry.name(getClass().getSimpleName(), "recordBatches")).time();
    Timer.Context timerBatchTypeSuccess = fileEventMetrics.timer(MetricRegistry.name(getClass().getSimpleName(), "recordBatches", rifFileType.name())).time();
    Timer.Context timerBundleFailure = appState.getMetrics().timer(MetricRegistry.name(getClass().getSimpleName(), "recordBatches", "failed")).time();
    EntityManager entityManager = null;
    EntityTransaction txn = null;
    // TODO: refactor the following to be less of an indented mess
    try {
        entityManager = appState.getEntityManagerFactory().createEntityManager();
        txn = entityManager.getTransaction();
        txn.begin();
        List<RifRecordLoadResult> loadResults = new ArrayList<>(recordsBatch.size());
        /*
       * Dev Note: All timestamps of records in the batch and the LoadedBatch must be the same for data consistency.
       * The timestamp from the LoadedBatchBuilder is used.
       */
        LoadedBatchBuilder loadedBatchBuilder = new LoadedBatchBuilder(loadedFileId, recordsBatch.size());
        for (RifRecordEvent<?> rifRecordEvent : recordsBatch) {
            RecordAction recordAction = rifRecordEvent.getRecordAction();
            RifRecordBase record = rifRecordEvent.getRecord();
            LOGGER.trace("Loading '{}' record.", rifFileType);
            // Set lastUpdated to the same value for the whole batch
            record.setLastUpdated(Optional.of(loadedBatchBuilder.getTimestamp()));
            // Associate the beneficiary with this file loaded
            loadedBatchBuilder.associateBeneficiary(rifRecordEvent.getBeneficiaryId());
            LoadStrategy strategy = selectStrategy(recordAction);
            LoadAction loadAction;
            if (strategy == LoadStrategy.INSERT_IDEMPOTENT) {
                // Check to see if record already exists.
                Timer.Context timerIdempotencyQuery = fileEventMetrics.timer(MetricRegistry.name(getClass().getSimpleName(), "idempotencyQueries")).time();
                Object recordId = appState.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier(record);
                Objects.requireNonNull(recordId);
                Object recordInDb = entityManager.find(record.getClass(), recordId);
                timerIdempotencyQuery.close();
                // Log if we have a non-2022 enrollment year INSERT
                if (isBackdatedBene(rifRecordEvent)) {
                    Beneficiary bene = (Beneficiary) rifRecordEvent.getRecord();
                    LOGGER.info("Inserted beneficiary with non-2022 enrollment year (beneficiaryId={})", bene.getBeneficiaryId());
                }
                if (recordInDb == null) {
                    loadAction = LoadAction.INSERTED;
                    tweakIfBeneficiary(entityManager, loadedBatchBuilder, rifRecordEvent);
                    entityManager.persist(record);
                // FIXME Object recordInDbAfterUpdate = entityManager.find(record.getClass(), recordId);
                } else {
                    loadAction = LoadAction.DID_NOTHING;
                }
            } else if (strategy == LoadStrategy.INSERT_UPDATE_NON_IDEMPOTENT) {
                if (rifRecordEvent.getRecordAction().equals(RecordAction.INSERT)) {
                    loadAction = LoadAction.INSERTED;
                    // Log if we have a non-2022 enrollment year INSERT
                    if (isBackdatedBene(rifRecordEvent)) {
                        Beneficiary bene = (Beneficiary) rifRecordEvent.getRecord();
                        LOGGER.info("Inserted beneficiary with non-2022 enrollment year (beneficiaryId={})", bene.getBeneficiaryId());
                    }
                    tweakIfBeneficiary(entityManager, loadedBatchBuilder, rifRecordEvent);
                    entityManager.persist(record);
                } else if (rifRecordEvent.getRecordAction().equals(RecordAction.UPDATE)) {
                    loadAction = LoadAction.UPDATED;
                    // Skip this record if the year is not 2022 and its an update.
                    if (isBackdatedBene(rifRecordEvent)) {
                        /*
               * Serialize the record's CSV data back to actual RIF/CSV, as that's how we'll store
               * it in the DB.
               */
                        StringBuffer rifData = new StringBuffer();
                        try (CSVPrinter csvPrinter = new CSVPrinter(rifData, RifParsingUtils.CSV_FORMAT)) {
                            for (CSVRecord csvRow : rifRecordEvent.getRawCsvRecords()) {
                                csvPrinter.printRecord(csvRow);
                            }
                        }
                        // Save the skipped record to the DB.
                        SkippedRifRecord skippedRifRecord = new SkippedRifRecord(rifRecordEvent.getFileEvent().getParentFilesEvent().getTimestamp(), SkipReasonCode.DELAYED_BACKDATED_ENROLLMENT_BFD_1566, rifRecordEvent.getFileEvent().getFile().getFileType().name(), rifRecordEvent.getRecordAction(), ((Beneficiary) record).getBeneficiaryId(), rifData.toString());
                        entityManager.persist(skippedRifRecord);
                        LOGGER.info("Skipped RIF record, due to '{}'.", skippedRifRecord.getSkipReason());
                    } else {
                        tweakIfBeneficiary(entityManager, loadedBatchBuilder, rifRecordEvent);
                        entityManager.merge(record);
                    }
                } else {
                    throw new BadCodeMonkeyException(String.format("Unhandled %s: '%s'.", RecordAction.class, rifRecordEvent.getRecordAction()));
                }
            } else
                throw new BadCodeMonkeyException();
            LOGGER.trace("Loaded '{}' record.", rifFileType);
            fileEventMetrics.meter(MetricRegistry.name(getClass().getSimpleName(), "records", loadAction.name())).mark(1);
            loadResults.add(new RifRecordLoadResult(rifRecordEvent, loadAction));
        }
        LoadedBatch loadedBatch = loadedBatchBuilder.build();
        entityManager.persist(loadedBatch);
        txn.commit();
        // Update the metrics now that things have been pushed.
        timerBatchSuccess.stop();
        timerBatchTypeSuccess.stop();
        return loadResults;
    } catch (Throwable t) {
        timerBundleFailure.stop();
        fileEventMetrics.meter(MetricRegistry.name(getClass().getSimpleName(), "recordBatches", "failed")).mark(1);
        LOGGER.warn("Failed to load '{}' record.", rifFileType, t);
        throw new RifLoadFailure(recordsBatch, t);
    } finally {
        /*
       * Some errors (e.g. HSQL constraint violations) seem to cause the
       * rollback to fail. Extra error handling is needed here, too, to
       * ensure that the failing data is captured.
       */
        try {
            if (txn != null && txn.isActive())
                txn.rollback();
        } catch (Throwable t) {
            timerBundleFailure.stop();
            fileEventMetrics.meter(MetricRegistry.name(getClass().getSimpleName(), "recordBatches", "failed")).mark(1);
            LOGGER.warn("Failed to load '{}' record.", rifFileType, t);
            throw new RifLoadFailure(recordsBatch, t);
        }
        if (entityManager != null)
            entityManager.close();
    }
}
Also used : RifFileEvent(gov.cms.bfd.model.rif.RifFileEvent) ArrayList(java.util.ArrayList) SkippedRifRecord(gov.cms.bfd.model.rif.SkippedRifRecord) RifFileType(gov.cms.bfd.model.rif.RifFileType) LoadedBatchBuilder(gov.cms.bfd.model.rif.LoadedBatchBuilder) CSVPrinter(org.apache.commons.csv.CSVPrinter) LoadAction(gov.cms.bfd.pipeline.ccw.rif.load.RifRecordLoadResult.LoadAction) RifRecordBase(gov.cms.bfd.model.rif.RifRecordBase) EntityTransaction(javax.persistence.EntityTransaction) BadCodeMonkeyException(gov.cms.bfd.sharedutils.exceptions.BadCodeMonkeyException) MetricRegistry(com.codahale.metrics.MetricRegistry) EntityManager(javax.persistence.EntityManager) Timer(com.codahale.metrics.Timer) RecordAction(gov.cms.bfd.model.rif.RecordAction) CSVRecord(org.apache.commons.csv.CSVRecord) Beneficiary(gov.cms.bfd.model.rif.Beneficiary) LoadedBatch(gov.cms.bfd.model.rif.LoadedBatch)

Example 8 with RecordAction

use of gov.cms.bfd.model.rif.RecordAction in project beneficiary-fhir-data by CMSgov.

the class RifFilesProcessor method buildHHAClaimEvent.

/**
 * @param fileEvent the {@link RifFileEvent} being processed
 * @param csvRecords the {@link CSVRecord}s to be mapped, which must be from a {@link
 *     RifFileType#HHA} {@link RifFile}
 * @return a {@link RifRecordEvent} built from the specified {@link CSVRecord}s
 */
private static RifRecordEvent<HHAClaim> buildHHAClaimEvent(RifFileEvent fileEvent, List<CSVRecord> csvRecords) {
    if (LOGGER.isTraceEnabled())
        LOGGER.trace(csvRecords.toString());
    CSVRecord firstCsvRecord = csvRecords.get(0);
    RecordAction recordAction = RecordAction.match(firstCsvRecord.get("DML_IND"));
    HHAClaim claim = HHAClaimParser.parseRif(csvRecords);
    return new RifRecordEvent<HHAClaim>(fileEvent, csvRecords, recordAction, claim.getBeneficiaryId(), claim);
}
Also used : HHAClaim(gov.cms.bfd.model.rif.HHAClaim) RifRecordEvent(gov.cms.bfd.model.rif.RifRecordEvent) CSVRecord(org.apache.commons.csv.CSVRecord) RecordAction(gov.cms.bfd.model.rif.RecordAction)

Example 9 with RecordAction

use of gov.cms.bfd.model.rif.RecordAction in project beneficiary-fhir-data by CMSgov.

the class RifFilesProcessor method buildDMEClaimEvent.

/**
 * @param fileEvent the {@link RifFileEvent} being processed
 * @param csvRecords the {@link CSVRecord}s to be mapped, which must be from a {@link
 *     RifFileType#DME} {@link RifFile}
 * @return a {@link RifRecordEvent} built from the specified {@link CSVRecord}s
 */
private static RifRecordEvent<DMEClaim> buildDMEClaimEvent(RifFileEvent fileEvent, List<CSVRecord> csvRecords) {
    if (LOGGER.isTraceEnabled())
        LOGGER.trace(csvRecords.toString());
    CSVRecord firstCsvRecord = csvRecords.get(0);
    RecordAction recordAction = RecordAction.match(firstCsvRecord.get("DML_IND"));
    DMEClaim claim = DMEClaimParser.parseRif(csvRecords);
    return new RifRecordEvent<DMEClaim>(fileEvent, csvRecords, recordAction, claim.getBeneficiaryId(), claim);
}
Also used : DMEClaim(gov.cms.bfd.model.rif.DMEClaim) RifRecordEvent(gov.cms.bfd.model.rif.RifRecordEvent) CSVRecord(org.apache.commons.csv.CSVRecord) RecordAction(gov.cms.bfd.model.rif.RecordAction)

Example 10 with RecordAction

use of gov.cms.bfd.model.rif.RecordAction in project beneficiary-fhir-data by CMSgov.

the class RifFilesProcessor method buildBeneficiaryEvent.

/**
 * @param fileEvent the {@link RifFileEvent} being processed
 * @param csvRecords the {@link CSVRecord} to be mapped (in a single-element {@link List}), which
 *     must be from a {@link RifFileType#BENEFICIARY} {@link RifFile}
 * @return a {@link RifRecordEvent} built from the specified {@link CSVRecord}s
 */
private static RifRecordEvent<Beneficiary> buildBeneficiaryEvent(RifFileEvent fileEvent, List<CSVRecord> csvRecords) {
    if (csvRecords.size() != 1)
        throw new BadCodeMonkeyException();
    CSVRecord csvRecord = csvRecords.get(0);
    if (LOGGER.isTraceEnabled())
        LOGGER.trace(csvRecord.toString());
    RecordAction recordAction = RecordAction.match(csvRecord.get("DML_IND"));
    Beneficiary beneficiaryRow = BeneficiaryParser.parseRif(csvRecords);
    // Swap the unhashed HICN into the correct field.
    beneficiaryRow.setHicnUnhashed(Optional.ofNullable(beneficiaryRow.getHicn()));
    beneficiaryRow.setHicn(null);
    return new RifRecordEvent<Beneficiary>(fileEvent, csvRecords, recordAction, beneficiaryRow.getBeneficiaryId(), beneficiaryRow);
}
Also used : BadCodeMonkeyException(gov.cms.bfd.sharedutils.exceptions.BadCodeMonkeyException) RifRecordEvent(gov.cms.bfd.model.rif.RifRecordEvent) CSVRecord(org.apache.commons.csv.CSVRecord) RecordAction(gov.cms.bfd.model.rif.RecordAction) Beneficiary(gov.cms.bfd.model.rif.Beneficiary)

Aggregations

RecordAction (gov.cms.bfd.model.rif.RecordAction)12 CSVRecord (org.apache.commons.csv.CSVRecord)12 RifRecordEvent (gov.cms.bfd.model.rif.RifRecordEvent)11 BadCodeMonkeyException (gov.cms.bfd.sharedutils.exceptions.BadCodeMonkeyException)5 Beneficiary (gov.cms.bfd.model.rif.Beneficiary)2 MetricRegistry (com.codahale.metrics.MetricRegistry)1 Timer (com.codahale.metrics.Timer)1 BeneficiaryHistory (gov.cms.bfd.model.rif.BeneficiaryHistory)1 CarrierClaim (gov.cms.bfd.model.rif.CarrierClaim)1 DMEClaim (gov.cms.bfd.model.rif.DMEClaim)1 HHAClaim (gov.cms.bfd.model.rif.HHAClaim)1 HospiceClaim (gov.cms.bfd.model.rif.HospiceClaim)1 InpatientClaim (gov.cms.bfd.model.rif.InpatientClaim)1 LoadedBatch (gov.cms.bfd.model.rif.LoadedBatch)1 LoadedBatchBuilder (gov.cms.bfd.model.rif.LoadedBatchBuilder)1 MedicareBeneficiaryIdHistory (gov.cms.bfd.model.rif.MedicareBeneficiaryIdHistory)1 OutpatientClaim (gov.cms.bfd.model.rif.OutpatientClaim)1 PartDEvent (gov.cms.bfd.model.rif.PartDEvent)1 RifFileEvent (gov.cms.bfd.model.rif.RifFileEvent)1 RifFileType (gov.cms.bfd.model.rif.RifFileType)1