CMSgov/dpc-app

View on GitHub
dpc-common/src/main/java/gov/cms/dpc/common/utils/SeedProcessor.java

Summary

Maintainability
A
0 mins
Test Coverage
package gov.cms.dpc.common.utils;

import gov.cms.dpc.fhir.DPCIdentifierSystem;
import gov.cms.dpc.fhir.FHIRBuilders;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.dstu3.model.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Utility class for process the test attribution file.
 * Mostly used for testing, but also by the SeedCommand in the AttributionService
 */
public class SeedProcessor {

    private static final SecureRandom rand = new SecureRandom();

    private SeedProcessor() {
        // Not used
    }

    /**
     * Processes the provided attribution file and groups the patients by provider ID
     *
     * @param stream - {@link InputStream} of associations file to load
     * @return - {@link Map} of Provider IDs and a {@link List} of {@link Pair} of providerID and patientID
     * @throws IOException - throws if unable to read the input file
     */
    public static Map<String, List<Pair<String, String>>> extractProviderMap(InputStream stream) throws IOException {
        List<Pair<String, String>> providerPairs = new ArrayList<>();

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
            for (String line; (line = reader.readLine()) != null; ) {
                // We can ignore this, because it's not worth pulling in Guava just for this.
                final String[] splits = line.split(",", -1);

                providerPairs.add(Pair.of(splits[1], splits[0]));
            }
        }

        return providerPairs
                .stream()
                .collect(Collectors.groupingBy(Pair::getLeft));
    }


    /**
     * Creates a FHIR {@link Bundle} for the given {@link Map} entry, generated by the {@link SeedProcessor#extractProviderMap(InputStream)} function.
     * * For the {@link Bundle}, the first entry is the {@link Practitioner} resource, and all subsequent entries are {@link Patient} resources
     *
     * @param entry             - {@link Map#entry(Object, Object)} representing the providerID and a {@link List} of {@link Pair} objects containing both the providerID and the patientID
     * @param organizationID    - {@link UUID} of organization to register attribution group to
     * @param patientReferences - {@link Map} patient ID lookup map
     * @return - {@link Group} which attributes to the given {@link Patient} entities to the {@link Practitioner} entity.
     */
    public static Group generateAttributionGroup(Map.Entry<String, List<Pair<String, String>>> entry, UUID organizationID, Map<String, Reference> patientReferences) {

        final Group group = createBaseAttributionGroup(entry.getKey(), organizationID.toString());

        final List<Group.GroupMemberComponent> members = entry
                .getValue()
                .stream()
                .map(Pair::getRight)
                .map(patientReferences::get)
                .filter(Objects::nonNull)
                .map(ref -> {
                    final Group.GroupMemberComponent member = new Group.GroupMemberComponent();
                    member
                            .setInactive(false)
                            .setEntity(ref);
                    return member;
                })
                .collect(Collectors.toList());

        return group.setMember(members);
    }

    public static Bundle generateAttributionBundle(Map.Entry<String, List<Pair<String, String>>> entry, UUID organizationID) {

        final Bundle bundle = new Bundle();

        bundle.setId(new IdType("Roster", "12345"));
        bundle.setType(Bundle.BundleType.COLLECTION);

        // Create the provider with the necessary fields
        final Practitioner practitioner = new Practitioner();
        practitioner.addIdentifier().setValue(entry.getKey()).setSystem(DPCIdentifierSystem.NPPES.getSystem());
        practitioner.addName().addGiven("Test").setFamily("Provider");

        // Add the Organization ID
        FHIRBuilders.addOrganizationTag(practitioner, organizationID);

        bundle.addEntry().setResource(practitioner).setFullUrl("http://something.gov/" + practitioner.getIdentifierFirstRep().getValue());

        entry.getValue()
                .forEach((value) -> {
                    // Add some random values to the patient
                    final Patient patient = new Patient();
                    patient.addIdentifier().setValue(value.getRight()).setSystem(DPCIdentifierSystem.MBI.getSystem());
                    patient.addName().addGiven("Tester " + rand.nextInt()).setFamily("Patient");
                    patient.setBirthDate(new GregorianCalendar(2019, Calendar.MARCH, 1).getTime());
                    patient.setManagingOrganization(new Reference(new IdType("Organization", organizationID.toString())));
                    patient.setGender(Enumerations.AdministrativeGender.UNKNOWN);
                    final Bundle.BundleEntryComponent component = new Bundle.BundleEntryComponent();
                    component.setResource(patient);
                    component.setFullUrl("http://something.gov/" + patient.getIdentifierFirstRep().getValue());
                    bundle.addEntry(component);
                });
        return bundle;
    }

    public static Group createBaseAttributionGroup(String providerNPI, String organizationID) {

        final CodeableConcept attributionConcept = new CodeableConcept();
        attributionConcept.addCoding().setCode("attributed-to");

        final CodeableConcept NPIConcept = new CodeableConcept();
        NPIConcept.addCoding().setSystem(DPCIdentifierSystem.NPPES.getSystem()).setCode(providerNPI);
        final Group rosterGroup = new Group();
        rosterGroup.setType(Group.GroupType.PERSON);
        rosterGroup.setActive(true);
        rosterGroup.addCharacteristic()
                .setExclude(false)
                .setCode(attributionConcept)
                .setValue(NPIConcept);
        FHIRBuilders.addOrganizationTag(rosterGroup, UUID.fromString(organizationID));

        return rosterGroup;
    }
}