Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add notes and gender to patient bulk upload #6778

Merged
merged 13 commits into from
Oct 26, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ public static String parseGender(String g) {
public static final String NON_BINARY = "nonbinary";
public static final String TRANS_MAN = "transman";
public static final String TRANS_WOMAN = "transwoman";
private static final Set<String> GENDER_IDENTITIES =
public static final Set<String> GENDER_IDENTITIES =
Set.of(FEMALE, MALE, TRANS_WOMAN, TRANS_MAN, NON_BINARY, OTHER, REFUSED);

public static String parseGenderIdentity(String genderIdentityInput) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateEmail;
import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateEthnicity;
import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateFlexibleDate;
import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateGenderIdentity;
import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePhoneNumber;
import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePhoneNumberType;
import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateRace;
Expand Down Expand Up @@ -44,6 +45,8 @@ public class PatientUploadRow implements FileRow {
final ValueOrError residentCongregateSetting;
final ValueOrError role;
final ValueOrError email;
final ValueOrError genderIdentity;
final ValueOrError notes;

static final String FIRST_NAME = "first_name";
static final String LAST_NAME = "last_name";
Expand All @@ -58,6 +61,8 @@ public class PatientUploadRow implements FileRow {
static final String PHONE_NUMBER_TYPE = "phone_number_type";
static final String EMPLOYED_IN_HEALTHCARE = "employed_in_healthcare";
static final String RESIDENT_CONGREGATE_SETTING = "resident_congregate_setting";
static final String GENDER_IDENTITY = "gender_identity";
static final String ADDRESS_NOTES = "address_notes";

private static final List<String> requiredFields =
List.of(
Expand Down Expand Up @@ -99,6 +104,8 @@ public PatientUploadRow(Map<String, String> rawRow) {
getValue(rawRow, RESIDENT_CONGREGATE_SETTING, isRequired(RESIDENT_CONGREGATE_SETTING));
role = getValue(rawRow, "role", isRequired("role"));
email = getValue(rawRow, "email", isRequired("email"));
genderIdentity = getValue(rawRow, GENDER_IDENTITY, isRequired("genderIdentity"));
notes = getValue(rawRow, ADDRESS_NOTES, isRequired("notes"));
}

@Override
Expand All @@ -124,6 +131,7 @@ public List<FeedbackMessage> validateIndividualValues() {
errors.addAll(validateRace(race));
errors.addAll(validateBiologicalSex(biologicalSex));
errors.addAll(validateEthnicity(ethnicity));
errors.addAll(validateGenderIdentity(genderIdentity));

// housing, work, and role
errors.addAll(validateYesNoAnswer(residentCongregateSetting));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import lombok.Builder;
import lombok.Getter;
import org.hibernate.annotations.Type;

Expand Down Expand Up @@ -163,6 +164,56 @@ public Person(
this.notes = notes;
}

@Builder

Check notice

Code scanning / CodeQL

Use of default toString()

Default toString(): StreetAddress inherits toString() from Object, and so is not suitable for printing. Default toString(): Facility inherits toString() from Object, and so is not suitable for printing. Default toString(): Organization inherits toString() from Object, and so is not suitable for printing.
public Person(
Organization organization,
Facility facility,
String lookupId,
String firstName,
String middleName,
String lastName,
String suffix,
LocalDate birthDate,
StreetAddress address,
String country,
PersonRole role,
List<String> emails,
String race,
String ethnicity,
List<String> tribalAffiliation,
String gender,
String genderIdentity,
Boolean residentCongregateSetting,
Boolean employedInHealthcare,
String preferredLanguage,
TestResultDeliveryPreference testResultDeliveryPreference,
String notes) {

this(
organization,
lookupId,
firstName,
middleName,
lastName,
suffix,
birthDate,
address,
country,
role,
emails,
race,
ethnicity,
tribalAffiliation,
gender,
genderIdentity,
residentCongregateSetting,
employedInHealthcare,
preferredLanguage,
testResultDeliveryPreference,
notes);
this.facility = facility;
}

public Person(
Organization organization,
Facility facility,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,30 +116,35 @@ public CompletableFuture<Set<Person>> savePatients(byte[] content, UUID facility

// create new person with current organization, then add to new patients list
Person newPatient =
new Person(
currentOrganization,
assignedFacility.orElse(null),
null, // lookupid
extractedData.getFirstName().getValue(),
extractedData.getMiddleName().getValue(),
extractedData.getLastName().getValue(),
extractedData.getSuffix().getValue(),
parseUserShortDate(extractedData.getDateOfBirth().getValue()),
address,
country,
parsePersonRole(extractedData.getRole().getValue(), false),
extractedData.getEmail().getValue() == null
? Collections.emptyList()
: List.of(extractedData.getEmail().getValue()),
convertRaceToDatabaseValue(extractedData.getRace().getValue()),
convertEthnicityToDatabaseValue(extractedData.getEthnicity().getValue()),
null, // tribalAffiliation
convertSexToDatabaseValue(extractedData.getBiologicalSex().getValue()),
parseYesNoUnk(extractedData.getResidentCongregateSetting().getValue()),
parseYesNoUnk(extractedData.getEmployedInHealthcare().getValue()),
null, // preferredLanguage
null // testResultDeliveryPreference
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed these explicit nulls by not specifying them in the builder, but lmk if we want to add them back in.

);
Person.builder()
Copy link
Contributor Author

@fzhao99 fzhao99 Oct 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was super annoying to deal with the multi-param constructor off the person object so I added a new one with the Builder annotation to make it more manageable. Do recognize that we're adding an entirely new constructor to enable this though, so if folks have a better way to work with this large object lmk.

.organization(currentOrganization)
.facility(assignedFacility.orElse(null))
.birthDate(parseUserShortDate(extractedData.getDateOfBirth().getValue()))
.address(address)
.country(country)
.role(parsePersonRole(extractedData.getRole().getValue(), false))
.emails(
extractedData.getEmail().getValue() == null
? Collections.emptyList()
: List.of(extractedData.getEmail().getValue()))
.race(convertRaceToDatabaseValue(extractedData.getRace().getValue()))
.ethnicity(convertEthnicityToDatabaseValue(extractedData.getEthnicity().getValue()))
.gender(convertSexToDatabaseValue(extractedData.getBiologicalSex().getValue()))
.genderIdentity(extractedData.getGenderIdentity().getValue())
fzhao99 marked this conversation as resolved.
Show resolved Hide resolved
.residentCongregateSetting(
parseYesNoUnk(extractedData.getResidentCongregateSetting().getValue()))
.employedInHealthcare(
parseYesNoUnk(extractedData.getEmployedInHealthcare().getValue()))
.firstName(extractedData.getFirstName().getValue())
.middleName(extractedData.getMiddleName().getValue())
.lastName(extractedData.getLastName().getValue())
.suffix(extractedData.getSuffix().getValue())
.notes(extractedData.getNotes().getValue())
Copy link
Contributor Author

@fzhao99 fzhao99 Oct 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now since we're not doing any string interpolation this column can either get filled with null (if the columns aren't specified) or the empty string (if the column is specified but there isn't any value for that row.) I left it this way since we're doing the same thing in other places.

lmk if anyone prefers null or "" explicitly though I can go back and clean it up here / in other settings

.lookupId(null)
.tribalAffiliation(null)
.preferredLanguage(null)
.testResultDeliveryPreference(null)
.build();

if (!allPatients.contains(newPatient)) {
// collect phone numbers and associate them with the patient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static gov.cdc.usds.simplereport.api.Translators.CANADIAN_STATE_CODES;
import static gov.cdc.usds.simplereport.api.Translators.COUNTRY_CODES;
import static gov.cdc.usds.simplereport.api.Translators.GENDER_IDENTITIES;
import static gov.cdc.usds.simplereport.api.Translators.PAST_DATE_FLEXIBLE_FORMATTER;
import static gov.cdc.usds.simplereport.api.Translators.STATE_CODES;
import static gov.cdc.usds.simplereport.db.model.PersonUtils.BOARDING_HOUSE_LITERAL;
Expand Down Expand Up @@ -142,6 +143,7 @@ public class CsvValidatorUtils {
"u", UNKNOWN_LITERAL,
"a", "ambiguous",
"n", "not applicable");

private static final Set<String> ETHNICITY_VALUES =
Set.of(
HISPANIC_CODE, HISPANIC_LITERAL,
Expand Down Expand Up @@ -300,6 +302,10 @@ public static List<FeedbackMessage> validateBiologicalSex(ValueOrError input) {
return validateInSet(input, GENDER_VALUES);
}

public static List<FeedbackMessage> validateGenderIdentity(ValueOrError input) {
return validateInSet(input, GENDER_IDENTITIES);
}

public static List<FeedbackMessage> validateState(ValueOrError input) {
return validateInSet(input, VALID_STATE_CODES);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ void validPerson_savedToDatabase() throws IOException, ExecutionException, Inter
assertThat(patient.getEthnicity()).isEqualTo("not_hispanic");
assertThat(patient.getBirthDate()).isEqualTo(LocalDate.of(1980, 11, 3));
assertThat(patient.getGender()).isEqualTo("female");
assertThat(patient.getGenderIdentity()).isEqualTo("female");
assertThat(patient.getNotes()).isEqualTo("some address note");

assertThat(patient.getRole()).isEqualTo(PersonRole.STAFF);

assertThat(patient.getCountry()).isEqualTo("USA");
Expand Down Expand Up @@ -203,6 +206,8 @@ void validPersonWithEmptyOptional_savedToDatabase()
assertThat(patient.getCountry()).isEqualTo("USA");
assertThat(patient.getEmployedInHealthcare()).isFalse();
assertThat(patient.getResidentCongregateSetting()).isFalse();
assertThat(patient.getGenderIdentity()).isNull();
assertThat(patient.getNotes()).isNull();

List<PhoneNumber> phoneNumbers =
phoneNumberRepository.findAllByPersonInternalId(patient.getInternalId());
Expand Down Expand Up @@ -246,6 +251,8 @@ void validPersonWithAlternateValues_savedToDatabase()
assertThat(patient.getCountry()).isEqualTo("USA");
assertThat(patient.getEmployedInHealthcare()).isNull();
assertThat(patient.getResidentCongregateSetting()).isNull();
assertThat(patient.getGenderIdentity()).isEmpty();
assertThat(patient.getNotes()).isEmpty();

List<PhoneNumber> phoneNumbers =
phoneNumberRepository.findAllByPersonInternalId(patient.getInternalId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ class PatientUploadRowTest {
"country",
"phone_number",
"phone_number_type",
"email");
"email",
"gender_identity");

@BeforeEach
public void init() {
Expand All @@ -69,6 +70,8 @@ public void init() {
validRowMap.put("resident_congregate_setting", "No");
validRowMap.put("role", "Staff");
validRowMap.put("email", "[email protected]");
validRowMap.put("gender_identity", "female");
validRowMap.put("address_notes", "test address notes");
}

@Test
Expand Down Expand Up @@ -103,6 +106,9 @@ void processRowSetsAllValues() {
.isEqualTo(validRowMap.get("resident_congregate_setting"));
assertThat(patientUploadRow.getRole().getValue()).isEqualTo(validRowMap.get("role"));
assertThat(patientUploadRow.getEmail().getValue()).isEqualTo(validRowMap.get("email"));
assertThat(patientUploadRow.getGenderIdentity().getValue())
.isEqualTo(validRowMap.get("gender_identity"));
assertThat(patientUploadRow.getNotes().getValue()).isEqualTo(validRowMap.get("address_notes"));
}

@Test
Expand Down Expand Up @@ -134,6 +140,7 @@ void validateIndividualFields() {
invalidIndividualValues.put("phone_number", "1");
invalidIndividualValues.put("phone_number_type", "cell");
invalidIndividualValues.put("email", "email");
invalidIndividualValues.put("gender_identity", "not a gender identity");

var patientUploadRow = new PatientUploadRow(invalidIndividualValues);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
last_name,first_name,middle_name,suffix,race,date_of_birth,biological_sex,ethnicity,street,street_2,city,county,state,zip_code,phone_number,phone_number_type,employed_in_healthcare,resident_congregate_setting,role,email
Sporer,Foobar,,,2028-9,6/12/40,A,2186-5,838 Waelchi Extensions,,Palm Bay,,AK,99501,410-881-4268,Landline,U,Unk,Staff,[email protected]
last_name,first_name,middle_name,suffix,race,date_of_birth,biological_sex,ethnicity,street,street_2,city,county,state,zip_code,phone_number,phone_number_type,employed_in_healthcare,resident_congregate_setting,role,email,gender_identity,address_notes
Sporer,Foobar,,,2028-9,6/12/40,A,2186-5,838 Waelchi Extensions,,Palm Bay,,AK,99501,410-881-4268,Landline,U,Unk,Staff,[email protected],,
4 changes: 2 additions & 2 deletions backend/src/test/resources/patientBulkUpload/valid.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
last_name,first_name,middle_name,suffix,race,date_of_birth,biological_sex,ethnicity,street,street_2,city,county,state,zip_code,phone_number,phone_number_type,employed_in_healthcare,resident_congregate_setting,role,email
Doe,Jane,Amanda,,black or african american,11/3/80,Female,not hispanic or latino,1234 Main Street,Apt 2,Anchorage,,AK,99501,410-867-5309,mobile,No,No,Staff,[email protected]
last_name,first_name,middle_name,suffix,race,date_of_birth,biological_sex,ethnicity,street,street_2,city,county,state,zip_code,phone_number,phone_number_type,employed_in_healthcare,resident_congregate_setting,role,email,gender_identity,address_notes
Doe,Jane,Amanda,,black or african american,11/3/80,Female,not hispanic or latino,1234 Main Street,Apt 2,Anchorage,,AK,99501,410-867-5309,mobile,No,No,Staff,[email protected],female,some address note