diff --git a/product-updates/knowledge-center/FTANF_2009.zip b/product-updates/knowledge-center/FTANF_2009.zip index 763a09a1e..f148fef1d 100644 Binary files a/product-updates/knowledge-center/FTANF_2009.zip and b/product-updates/knowledge-center/FTANF_2009.zip differ diff --git a/product-updates/knowledge-center/SSPMOE_2009.zip b/product-updates/knowledge-center/SSPMOE_2009.zip index 94458c7a0..b67f67043 100644 Binary files a/product-updates/knowledge-center/SSPMOE_2009.zip and b/product-updates/knowledge-center/SSPMOE_2009.zip differ diff --git a/product-updates/knowledge-center/ftanf.zip b/product-updates/knowledge-center/ftanf.zip index 6d6a0fc9a..d07c49205 100644 Binary files a/product-updates/knowledge-center/ftanf.zip and b/product-updates/knowledge-center/ftanf.zip differ diff --git a/tdrs-backend/tdpservice/parsers/parse.py b/tdrs-backend/tdpservice/parsers/parse.py index 7b5177e74..dbe80980b 100644 --- a/tdrs-backend/tdpservice/parsers/parse.py +++ b/tdrs-backend/tdpservice/parsers/parse.py @@ -28,11 +28,31 @@ def parse_datafile(datafile): bulk_create_errors({1: header_errors}, 1, flush=True) return errors - is_encrypted = util.contains_encrypted_indicator(header_line, schema_defs.header.get_field_by_name("encryption")) + field_values = schema_defs.header.get_field_values_by_names(header_line, + {"encryption", "tribe_code", "state_fips"}) + + # Validate tribe code in submission across program type and fips code + generate_error = util.make_generate_parser_error(datafile, 1) + tribe_is_valid, tribe_error = validators.validate_tribe_fips_program_agree(header['program_type'], + field_values["tribe_code"], + field_values["state_fips"], + generate_error) + + if not tribe_is_valid: + logger.info(f"Tribe Code ({field_values['tribe_code']}) inconsistency with Program Type " + + f"({header['program_type']}) and FIPS Code ({field_values['state_fips']}).",) + errors['header'] = [tribe_error] + bulk_create_errors({1: [tribe_error]}, 1, flush=True) + return errors + + is_encrypted = field_values["encryption"] == "E" + is_tribal = not validators.value_is_empty(field_values["tribe_code"], 3, extra_vals={'0'*3}) + logger.debug(f"Datafile has encrypted fields: {is_encrypted}.") + logger.debug(f"Datafile: {datafile.__repr__()}, is Tribal: {is_tribal}.") # ensure file section matches upload section - program_type = header['program_type'] + program_type = f"Tribal {header['program_type']}" if is_tribal else header['program_type'] section = header['type'] logger.debug(f"Program type: {program_type}, Section: {section}.") diff --git a/tdrs-backend/tdpservice/parsers/row_schema.py b/tdrs-backend/tdpservice/parsers/row_schema.py index 97a9ccc65..126fb1f4d 100644 --- a/tdrs-backend/tdpservice/parsers/row_schema.py +++ b/tdrs-backend/tdpservice/parsers/row_schema.py @@ -168,6 +168,14 @@ def run_postparsing_validators(self, instance, generate_error): return is_valid, errors + def get_field_values_by_names(self, line, names={}): + """Return dictionary of field values keyed on their name.""" + field_values = {} + for field in self.fields: + if field.name in names: + field_values[field.name] = field.parse_value(line) + return field_values + def get_field_by_name(self, name): """Get field by it's name.""" for field in self.fields: diff --git a/tdrs-backend/tdpservice/parsers/schema_defs/__init__.py b/tdrs-backend/tdpservice/parsers/schema_defs/__init__.py index f79fe3075..3122c2451 100644 --- a/tdrs-backend/tdpservice/parsers/schema_defs/__init__.py +++ b/tdrs-backend/tdpservice/parsers/schema_defs/__init__.py @@ -1,9 +1,11 @@ from .header import header from .trailer import trailer from . import tanf +from . import tribal_tanf from . import ssp header = header trailer = trailer tanf = tanf +tribal_tanf = tribal_tanf ssp = ssp diff --git a/tdrs-backend/tdpservice/parsers/schema_defs/header.py b/tdrs-backend/tdpservice/parsers/schema_defs/header.py index a36d4d82f..5a9960af1 100644 --- a/tdrs-backend/tdpservice/parsers/schema_defs/header.py +++ b/tdrs-backend/tdpservice/parsers/schema_defs/header.py @@ -66,13 +66,17 @@ type="string", startIndex=12, endIndex=14, - required=True, + required=False, validators=[ - validators.oneOf(("01", "02", "04", "05", "06", "08", "09", "10", "11", "12", "13", "15", - "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", - "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", - "40", "41", "42", "44", "45", "46", "47", "48", "49", "50", "51", "53", - "54", "55", "56", "66", "72", "78")) + validators.or_validators( + validators.isInStringRange(0, 2), + validators.isInStringRange(4, 6), + validators.isInStringRange(8, 13), + validators.isInStringRange(15, 42), + validators.isInStringRange(44, 51), + validators.isInStringRange(53, 56), + validators.oneOf(["66", "72", "78"]), + ) ], ), Field( diff --git a/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/__init__.py b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/__init__.py new file mode 100644 index 000000000..a0727f36b --- /dev/null +++ b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/__init__.py @@ -0,0 +1,7 @@ +from .t1 import t1 +from .t2 import t2 +from .t3 import t3 + +t1 = t1 +t2 = t2 +t3 = t3 diff --git a/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t1.py b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t1.py new file mode 100644 index 000000000..2820b76fa --- /dev/null +++ b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t1.py @@ -0,0 +1,668 @@ +"""Schema for Tribal TANF T1 record types.""" + +from ...util import SchemaManager +from ...fields import Field +from ...row_schema import RowSchema +from ... import validators +from tdpservice.search_indexes.models.tribal import Tribal_TANF_T1 + + +t1 = SchemaManager( + schemas=[ + RowSchema( + model=Tribal_TANF_T1, + preparsing_validators=[ + validators.hasLength(122), + ], + postparsing_validators=[ + validators.if_then_validator( + condition_field="CASH_AMOUNT", + condition_function=validators.isLargerThan(0), + result_field="NBR_MONTHS", + result_function=validators.isLargerThan(0), + ), + validators.if_then_validator( + condition_field="CC_AMOUNT", + condition_function=validators.isLargerThan(0), + result_field="CHILDREN_COVERED", + result_function=validators.isLargerThan(0), + ), + validators.if_then_validator( + condition_field="CC_AMOUNT", + condition_function=validators.isLargerThan(0), + result_field="CC_NBR_MONTHS", + result_function=validators.isLargerThan(0), + ), + validators.if_then_validator( + condition_field="TRANSP_AMOUNT", + condition_function=validators.isLargerThan(0), + result_field="TRANSP_NBR_MONTHS", + result_function=validators.isLargerThan(0), + ), + validators.if_then_validator( + condition_field="TRANSITION_SERVICES_AMOUNT", + condition_function=validators.isLargerThan(0), + result_field="TRANSITION_NBR_MONTHS", + result_function=validators.isLargerThan(0), + ), + validators.if_then_validator( + condition_field="OTHER_AMOUNT", + condition_function=validators.isLargerThan(0), + result_field="OTHER_NBR_MONTHS", + result_function=validators.isLargerThan(0), + ), + validators.if_then_validator( + condition_field="SANC_REDUCTION_AMT", + condition_function=validators.isLargerThan(0), + result_field="WORK_REQ_SANCTION", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="SANC_REDUCTION_AMT", + condition_function=validators.isLargerThan(0), + result_field="FAMILY_SANC_ADULT", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="SANC_REDUCTION_AMT", + condition_function=validators.isLargerThan(0), + result_field="SANC_TEEN_PARENT", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="SANC_REDUCTION_AMT", + condition_function=validators.isLargerThan(0), + result_field="NON_COOPERATION_CSE", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="SANC_REDUCTION_AMT", + condition_function=validators.isLargerThan(0), + result_field="FAILURE_TO_COMPLY", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="SANC_REDUCTION_AMT", + condition_function=validators.isLargerThan(0), + result_field="OTHER_SANCTION", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="OTHER_TOTAL_REDUCTIONS", + condition_function=validators.isLargerThan(0), + result_field="FAMILY_CAP", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="OTHER_TOTAL_REDUCTIONS", + condition_function=validators.isLargerThan(0), + result_field="REDUCTIONS_ON_RECEIPTS", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="OTHER_TOTAL_REDUCTIONS", + condition_function=validators.isLargerThan(0), + result_field="OTHER_NON_SANCTION", + result_function=validators.oneOf((1, 2)), + ), + validators.sumIsLarger( + ( + "AMT_FOOD_STAMP_ASSISTANCE", + "AMT_SUB_CC", + "CASH_AMOUNT", + "CC_AMOUNT", + "TRANSP_AMOUNT", + "TRANSITION_SERVICES_AMOUNT", + "OTHER_AMOUNT", + ), + 0, + ), + ], + fields=[ + Field( + item="0", + name="RecordType", + friendly_name="record type", + type="string", + startIndex=0, + endIndex=2, + required=True, + validators=[], + ), + Field( + item="4", + name="RPT_MONTH_YEAR", + friendly_name="reporting month year", + type="number", + startIndex=2, + endIndex=8, + required=True, + validators=[ + validators.dateYearIsLargerThan(1900), + validators.dateMonthIsValid(), + ], + ), + Field( + item="6", + name="CASE_NUMBER", + friendly_name="case number", + type="string", + startIndex=8, + endIndex=19, + required=True, + validators=[validators.isAlphaNumeric()], + ), + Field( + item="2", + name="COUNTY_FIPS_CODE", + friendly_name="county fips code", + type="string", + startIndex=19, + endIndex=22, + required=False, + validators=[ + validators.isNumber(), + ], + ), + Field( + item="5", + name="STRATUM", + friendly_name="stratum", + type="string", + startIndex=22, + endIndex=24, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="7", + name="ZIP_CODE", + friendly_name="zip code", + type="string", + startIndex=24, + endIndex=29, + required=True, + validators=[ + validators.isNumber(), + ], + ), + Field( + item="8", + name="FUNDING_STREAM", + friendly_name="funding stream", + type="number", + startIndex=29, + endIndex=30, + required=True, + validators=[ + validators.isInLimits(1, 2), + ], + ), + Field( + item="9", + name="DISPOSITION", + friendly_name="disposition", + type="number", + startIndex=30, + endIndex=31, + required=True, + validators=[ + validators.matches(1), + ], + ), + Field( + item="10", + name="NEW_APPLICANT", + friendly_name="new applicant", + type="number", + startIndex=31, + endIndex=32, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="11", + name="NBR_FAMILY_MEMBERS", + friendly_name="number of family members", + type="number", + startIndex=32, + endIndex=34, + required=True, + validators=[ + validators.isInLimits(1, 99), + ], + ), + Field( + item="12", + name="FAMILY_TYPE", + friendly_name="family type", + type="number", + startIndex=34, + endIndex=35, + required=True, + validators=[ + validators.isInLimits(1, 3), + ], + ), + Field( + item="13", + name="RECEIVES_SUB_HOUSING", + friendly_name="receives subsidized housing", + type="number", + startIndex=35, + endIndex=36, + required=True, + validators=[ + validators.isInLimits(1, 3), + ], + ), + Field( + item="14", + name="RECEIVES_MED_ASSISTANCE", + friendly_name="receives medical assistance", + type="number", + startIndex=36, + endIndex=37, + required=True, + validators=[ + validators.isInLimits(1, 2), + ], + ), + Field( + item="15", + name="RECEIVES_FOOD_STAMPS", + friendly_name="receives food stamps", + type="number", + startIndex=37, + endIndex=38, + required=False, + validators=[ + validators.isInLimits(0, 2), + ], + ), + Field( + item="16", + name="AMT_FOOD_STAMP_ASSISTANCE", + friendly_name="amount of food stamp assistance", + type="number", + startIndex=38, + endIndex=42, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="17", + name="RECEIVES_SUB_CC", + friendly_name="receives subsidized child care", + type="number", + startIndex=42, + endIndex=43, + required=False, + validators=[ + validators.isInLimits(0, 3), + ], + ), + Field( + item="18", + name="AMT_SUB_CC", + friendly_name="amount of subsidized child care", + type="number", + startIndex=43, + endIndex=47, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="19", + name="CHILD_SUPPORT_AMT", + friendly_name="child support amount", + type="number", + startIndex=47, + endIndex=51, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="20", + name="FAMILY_CASH_RESOURCES", + friendly_name="family cash resources", + type="number", + startIndex=51, + endIndex=55, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="21A", + name="CASH_AMOUNT", + friendly_name="cash amount", + type="number", + startIndex=55, + endIndex=59, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="21B", + name="NBR_MONTHS", + friendly_name="number of months", + type="number", + startIndex=59, + endIndex=62, + required=True, + validators=[ + validators.isInLimits(0, 999), + ], + ), + Field( + item="22A", + name="CC_AMOUNT", + friendly_name="child care amount", + type="number", + startIndex=62, + endIndex=66, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="22B", + name="CHILDREN_COVERED", + friendly_name="children covered", + type="number", + startIndex=66, + endIndex=68, + required=True, + validators=[ + validators.isInLimits(0, 99), + ], + ), + Field( + item="22C", + name="CC_NBR_MONTHS", + friendly_name="child care number of months", + type="number", + startIndex=68, + endIndex=71, + required=True, + validators=[ + validators.isInLimits(0, 999), + ], + ), + Field( + item="23A", + name="TRANSP_AMOUNT", + friendly_name="transportation amount", + type="number", + startIndex=71, + endIndex=75, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="23B", + name="TRANSP_NBR_MONTHS", + friendly_name="transportation number of months", + type="number", + startIndex=75, + endIndex=78, + required=True, + validators=[ + validators.isInLimits(0, 999), + ], + ), + Field( + item="24A", + name="TRANSITION_SERVICES_AMOUNT", + friendly_name="transition services amount", + type="number", + startIndex=78, + endIndex=82, + required=False, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="24B", + name="TRANSITION_NBR_MONTHS", + friendly_name="transition services number of months", + type="number", + startIndex=82, + endIndex=85, + required=False, + validators=[ + validators.isInLimits(0, 999), + ], + ), + Field( + item="25A", + name="OTHER_AMOUNT", + friendly_name="other amount", + type="number", + startIndex=85, + endIndex=89, + required=False, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="25B", + name="OTHER_NBR_MONTHS", + friendly_name="other number of months", + type="number", + startIndex=89, + endIndex=92, + required=False, + validators=[ + validators.isInLimits(0, 999), + ], + ), + Field( + item="26AI", + name="SANC_REDUCTION_AMT", + friendly_name="sanction reduction amount", + type="number", + startIndex=92, + endIndex=96, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="26AII", + name="WORK_REQ_SANCTION", + friendly_name="work requirement sanction", + type="number", + startIndex=96, + endIndex=97, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="26AIII", + name="FAMILY_SANC_ADULT", + friendly_name="family sanction adult", + type="number", + startIndex=97, + endIndex=98, + required=False, + validators=[ + validators.oneOf([0, 1, 2]), + ], + ), + Field( + item="26AIV", + name="SANC_TEEN_PARENT", + friendly_name="sanctioned teen parent", + type="number", + startIndex=98, + endIndex=99, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="26AV", + name="NON_COOPERATION_CSE", + friendly_name="non-cooperation with child support", + type="number", + startIndex=99, + endIndex=100, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="26AVI", + name="FAILURE_TO_COMPLY", + friendly_name="failure to comply", + type="number", + startIndex=100, + endIndex=101, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="26AVII", + name="OTHER_SANCTION", + friendly_name="other, sanction", + type="number", + startIndex=101, + endIndex=102, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="26B", + name="RECOUPMENT_PRIOR_OVRPMT", + friendly_name="recoupment prior overpayment", + type="number", + startIndex=102, + endIndex=106, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="26CI", + name="OTHER_TOTAL_REDUCTIONS", + friendly_name="other total reductions", + type="number", + startIndex=106, + endIndex=110, + required=True, + validators=[ + validators.isInLimits(0, 9999), + ], + ), + Field( + item="26CII", + name="FAMILY_CAP", + friendly_name="family cap", + type="number", + startIndex=110, + endIndex=111, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="26CIII", + name="REDUCTIONS_ON_RECEIPTS", + friendly_name="reductions on receipts", + type="number", + startIndex=111, + endIndex=112, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="26CIV", + name="OTHER_NON_SANCTION", + friendly_name="other, non-sanction", + type="number", + startIndex=112, + endIndex=113, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="27", + name="WAIVER_EVAL_CONTROL_GRPS", + friendly_name="waiver evaluation control groups", + type="string", + startIndex=113, + endIndex=114, + required=False, + validators=[validators.isInStringRange(0, 9)], + ), + Field( + item="28", + name="FAMILY_EXEMPT_TIME_LIMITS", + friendly_name="family exempt time limits", + type="number", + startIndex=114, + endIndex=116, + required=True, + validators=[validators.isInLimits(0, 9)], + ), + Field( + item="29", + name="FAMILY_NEW_CHILD", + friendly_name="family new child", + type="number", + startIndex=116, + endIndex=117, + required=False, + validators=[ + validators.oneOf([0, 1, 2]), + ], + ), + Field( + item="-1", + name="BLANK", + friendly_name="blank", + type="string", + startIndex=117, + endIndex=123, + required=False, + validators=[], + ), + ], + ) + ] +) diff --git a/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t2.py b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t2.py new file mode 100644 index 000000000..ed1d03e8d --- /dev/null +++ b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t2.py @@ -0,0 +1,740 @@ +"""Schema for Tribal TANF T2 row of all submission types.""" + + +from ...util import SchemaManager +from ...transforms import tanf_ssn_decryption_func +from ...fields import TransformField, Field +from ...row_schema import RowSchema +from ... import validators +from tdpservice.search_indexes.models.tribal import Tribal_TANF_T2 + + +t2 = SchemaManager( + schemas=[ + RowSchema( + model=Tribal_TANF_T2, + preparsing_validators=[ + validators.hasLength(122), + ], + postparsing_validators=[ + validators.validate__FAM_AFF__SSN(), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="SSN", + result_function=validators.validateSSN(), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="RACE_HISPANIC", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="RACE_AMER_INDIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="RACE_ASIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="RACE_BLACK", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="RACE_HAWAIIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="RACE_WHITE", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="MARITAL_STATUS", + result_function=validators.isInLimits(1, 5), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 2), + result_field="PARENT_MINOR_CHILD", + result_function=validators.isInLimits(1, 3), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="EDUCATION_LEVEL", + result_function=validators.or_validators( + validators.isInStringRange(0, 16), + validators.isInStringRange(98, 99), + ), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="CITIZENSHIP_STATUS", + result_function=validators.matches(1), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="COOPERATION_CHILD_SUPPORT", + result_function=validators.oneOf((1, 2, 9)), + ), + validators.validate__FAM_AFF__HOH__Fed_Time(), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.isInLimits(1, 3), + result_field="EMPLOYMENT_STATUS", + result_function=validators.isInLimits(1, 3), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="WORK_PART_STATUS", + result_function=validators.or_validators( + validators.isInStringRange(1, 3), + validators.isInStringRange(5, 9), + validators.isInStringRange(11, 19), + validators.matches("99"), + ), + ), + ], + fields=[ + Field( + item="0", + name="RecordType", + friendly_name="record type", + type="string", + startIndex=0, + endIndex=2, + required=True, + validators=[], + ), + Field( + item="4", + name="RPT_MONTH_YEAR", + friendly_name="reporting month and year", + type="number", + startIndex=2, + endIndex=8, + required=True, + validators=[ + validators.dateYearIsLargerThan(1900), + validators.dateMonthIsValid(), + ], + ), + Field( + item="6", + name="CASE_NUMBER", + friendly_name="case number", + type="string", + startIndex=8, + endIndex=19, + required=True, + validators=[validators.isAlphaNumeric()], + ), + Field( + item="30", + name="FAMILY_AFFILIATION", + friendly_name="family affiliation", + type="number", + startIndex=19, + endIndex=20, + required=True, + validators=[validators.oneOf([1, 2, 3, 5])], + ), + Field( + item="31", + name="NONCUSTODIAL_PARENT", + friendly_name="noncustodial parent", + type="number", + startIndex=20, + endIndex=21, + required=True, + validators=[validators.oneOf([1, 2])], + ), + Field( + item="32", + name="DATE_OF_BIRTH", + friendly_name="date of birth", + type="number", + startIndex=21, + endIndex=29, + required=True, + validators=[ + validators.dateYearIsLargerThan(1900), + validators.dateMonthIsValid(), + ], + ), + TransformField( + transform_func=tanf_ssn_decryption_func, + item="33", + name="SSN", + friendly_name="social security number - ssn", + type="string", + startIndex=29, + endIndex=38, + required=True, + validators=[validators.validateSSN()], + is_encrypted=False, + ), + Field( + item="34A", + name="RACE_HISPANIC", + friendly_name="race hispanic", + type="number", + startIndex=38, + endIndex=39, + required=False, + validators=[validators.isInLimits(0, 2)], + ), + Field( + item="34B", + name="RACE_AMER_INDIAN", + friendly_name="race american-indian", + type="number", + startIndex=39, + endIndex=40, + required=False, + validators=[validators.isInLimits(0, 2)], + ), + Field( + item="34C", + name="RACE_ASIAN", + friendly_name="race asian", + type="number", + startIndex=40, + endIndex=41, + required=False, + validators=[validators.isInLimits(0, 2)], + ), + Field( + item="34D", + name="RACE_BLACK", + friendly_name="race black", + type="number", + startIndex=41, + endIndex=42, + required=False, + validators=[validators.isInLimits(0, 2)], + ), + Field( + item="34E", + name="RACE_HAWAIIAN", + friendly_name="race hawaiian", + type="number", + startIndex=42, + endIndex=43, + required=False, + validators=[validators.isInLimits(0, 2)], + ), + Field( + item="34F", + name="RACE_WHITE", + friendly_name="race white", + type="number", + startIndex=43, + endIndex=44, + required=False, + validators=[validators.isInLimits(0, 2)], + ), + Field( + item="35", + name="GENDER", + friendly_name="gender", + type="number", + startIndex=44, + endIndex=45, + required=False, + validators=[ + validators.isLargerThanOrEqualTo(0), + ], + ), + Field( + item="36A", + name="FED_OASDI_PROGRAM", + friendly_name="federal old age survivors and disability insurance program", + type="number", + startIndex=45, + endIndex=46, + required=True, + validators=[validators.oneOf([1, 2])], + ), + Field( + item="36B", + name="FED_DISABILITY_STATUS", + friendly_name="federal disability status", + type="number", + startIndex=46, + endIndex=47, + required=True, + validators=[validators.oneOf([1, 2])], + ), + Field( + item="36C", + name="DISABLED_TITLE_XIVAPDT", + friendly_name="Receives Aid to the Permanently and Totally Disabled" + + " Under Title XIV-APDT of the Social Security Act", + type="string", + startIndex=47, + endIndex=48, + required=True, + validators=[ + validators.or_validators( + validators.oneOf(["1", "2"]), validators.isBlank() + ) + ], + ), + Field( + item="36D", + name="AID_AGED_BLIND", + friendly_name="receives from the aid to the aged, blind, and disabled program", + type="number", + startIndex=48, + endIndex=49, + required=False, + validators=[ + validators.isInLimits(0, 2), + ], + ), + Field( + item="36E", + name="RECEIVE_SSI", + friendly_name="receives social security income", + type="number", + startIndex=49, + endIndex=50, + required=True, + validators=[ + validators.oneOf([1, 2]), + ], + ), + Field( + item="37", + name="MARITAL_STATUS", + friendly_name="marital status", + type="number", + startIndex=50, + endIndex=51, + required=False, + validators=[ + validators.isInLimits(0, 5), + ], + ), + Field( + item="38", + name="RELATIONSHIP_HOH", + friendly_name="relationship to head of household", + type="string", + startIndex=51, + endIndex=53, + required=False, + validators=[ + validators.isInStringRange(0, 10), + ], + ), + Field( + item="39", + name="PARENT_WITH_MINOR_CHILD", + friendly_name="parent with minor child", + type="number", + startIndex=53, + endIndex=54, + required=False, + validators=[ + validators.isInLimits(0, 3), + ], + ), + Field( + item="40", + name="NEEDS_PREGNANT_WOMAN", + friendly_name="needs of pregnant woman", + type="number", + startIndex=54, + endIndex=55, + required=False, + validators=[ + validators.isInLimits(0, 2), + ], + ), + Field( + item="41", + name="EDUCATION_LEVEL", + friendly_name="education level", + type="string", + startIndex=55, + endIndex=57, + required=False, + validators=[ + validators.or_validators( + validators.isInStringRange(0, 16), + validators.isInStringRange(98, 99), + ) + ], + ), + Field( + item="42", + name="CITIZENSHIP_STATUS", + friendly_name="citizenship status", + type="number", + startIndex=57, + endIndex=58, + required=False, + validators=[validators.oneOf([0, 1, 2, 9])], + ), + Field( + item="43", + name="COOPERATION_CHILD_SUPPORT", + friendly_name="cooperation with child support", + type="number", + startIndex=58, + endIndex=59, + required=False, + validators=[ + validators.oneOf([0, 1, 2, 9]), + ], + ), + Field( + item="44", + name="MONTHS_FED_TIME_LIMIT", + friendly_name="countable months toward federal time limit", + type="string", + startIndex=59, + endIndex=62, + required=False, + validators=[ + validators.isInStringRange(0, 999), + ], + ), + Field( + item="45", + name="MONTHS_STATE_TIME_LIMIT", + friendly_name="months of state time limit", + type="string", + startIndex=62, + endIndex=64, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="46", + name="CURRENT_MONTH_STATE_EXEMPT", + friendly_name="current month state exempt", + type="number", + startIndex=64, + endIndex=65, + required=False, + validators=[ + validators.isInLimits(0, 2), + ], + ), + Field( + item="47", + name="EMPLOYMENT_STATUS", + friendly_name="employment status", + type="number", + startIndex=65, + endIndex=66, + required=False, + validators=[ + validators.isInLimits(0, 3), + ], + ), + Field( + item="48", + name="WORK_PART_STATUS", + friendly_name="work participation status", + type="string", + startIndex=66, + endIndex=68, + required=False, + validators=[ + validators.or_validators( + validators.isInStringRange(0, 3), + validators.isInStringRange(5, 9), + validators.isInStringRange(11, 19), + validators.matches("99"), + ) + ], + ), + Field( + item="49", + name="UNSUB_EMPLOYMENT", + friendly_name="unsubsidized employment", + type="string", + startIndex=68, + endIndex=70, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="50", + name="SUB_PRIVATE_EMPLOYMENT", + friendly_name="subsidized private employment", + type="string", + startIndex=70, + endIndex=72, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="51", + name="SUB_PUBLIC_EMPLOYMENT", + friendly_name="subsidized public employment", + type="string", + startIndex=72, + endIndex=74, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="52", + name="WORK_EXPERIENCE", + friendly_name="work experience", + type="string", + startIndex=74, + endIndex=76, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="53", + name="OJT", + friendly_name="on the job training", + type="string", + startIndex=76, + endIndex=78, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="54", + name="JOB_SEARCH", + friendly_name="job search", + type="string", + startIndex=78, + endIndex=80, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="55", + name="COMM_SERVICES", + friendly_name="community service", + type="string", + startIndex=80, + endIndex=82, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="56", + name="VOCATIONAL_ED_TRAINING", + friendly_name="vocational education", + type="string", + startIndex=82, + endIndex=84, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="57", + name="JOB_SKILLS_TRAINING", + friendly_name="job skills training", + type="string", + startIndex=84, + endIndex=86, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="58", + name="ED_NO_HIGH_SCHOOL_DIPLOMA", + friendly_name="education no high school diploma", + type="string", + startIndex=86, + endIndex=88, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="59", + name="SCHOOL_ATTENDENCE", + friendly_name="school attendance", + type="string", + startIndex=88, + endIndex=90, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="60", + name="PROVIDE_CC", + friendly_name="provide child care", + type="string", + startIndex=90, + endIndex=92, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="61", + name="ADD_WORK_ACTIVITIES", + friendly_name="additional work activities", + type="string", + startIndex=92, + endIndex=94, + required=False, + validators=[ + validators.matches("00"), + ], + ), + Field( + item="62", + name="OTHER_WORK_ACTIVITIES", + friendly_name="other work activities", + type="string", + startIndex=94, + endIndex=96, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="63", + name="REQ_HRS_WAIVER_DEMO", + friendly_name="required hours under waiver demo", + type="string", + startIndex=96, + endIndex=98, + required=False, + validators=[ + validators.isInStringRange(0, 99), + ], + ), + Field( + item="64", + name="EARNED_INCOME", + friendly_name="earned income", + type="string", + startIndex=98, + endIndex=102, + required=False, + validators=[ + validators.isInStringRange(0, 9999), + ], + ), + Field( + item="65A", + name="UNEARNED_INCOME_TAX_CREDIT", + friendly_name="unearned income tax credit", + type="string", + startIndex=102, + endIndex=106, + required=False, + validators=[ + validators.isInStringRange(0, 9999), + ], + ), + Field( + item="65B", + name="UNEARNED_SOCIAL_SECURITY", + friendly_name="unearned social security", + type="string", + startIndex=106, + endIndex=110, + required=True, + validators=[ + validators.isInStringRange(0, 9999), + ], + ), + Field( + item="65C", + name="UNEARNED_SSI", + friendly_name="unearned ssi benefit", + type="string", + startIndex=110, + endIndex=114, + required=True, + validators=[ + validators.isInStringRange(0, 9999), + ], + ), + Field( + item="65D", + name="UNEARNED_WORKERS_COMP", + friendly_name="unearned workers compensation", + type="string", + startIndex=114, + endIndex=118, + required=True, + validators=[ + validators.isInStringRange(0, 9999), + ], + ), + Field( + item="65E", + name="OTHER_UNEARNED_INCOME", + friendly_name="other unearned income", + type="string", + startIndex=118, + endIndex=122, + required=True, + validators=[ + validators.isInStringRange(0, 9999), + ], + ), + Field( + item="-1", + name="BLANK", + friendly_name="blank", + type="string", + startIndex=122, + endIndex=123, + required=False, + validators=[], + ), + ], + ) + ] +) diff --git a/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t3.py b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t3.py new file mode 100644 index 000000000..4d68ec457 --- /dev/null +++ b/tdrs-backend/tdpservice/parsers/schema_defs/tribal_tanf/t3.py @@ -0,0 +1,620 @@ +"""Schema for Tribal TANF T3 row of all submission types.""" + + +from ...util import SchemaManager +from ...transforms import tanf_ssn_decryption_func +from ...fields import TransformField, Field +from ...row_schema import RowSchema +from ... import validators +from tdpservice.search_indexes.models.tribal import Tribal_TANF_T3 + + +child_one = RowSchema( + model=Tribal_TANF_T3, + preparsing_validators=[ + validators.notEmpty(start=19, end=60), + validators.hasLength(122), + ], + postparsing_validators=[ + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="SSN", + result_function=validators.validateSSN(), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_HISPANIC", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_AMER_INDIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_ASIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_BLACK", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_HAWAIIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_WHITE", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RELATIONSHIP_HOH", + result_function=validators.isInStringRange(4, 9), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="PARENT_MINOR_CHILD", + result_function=validators.oneOf((2, 3)), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="EDUCATION_LEVEL", + result_function=validators.notMatches("99"), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="CITIZENSHIP_STATUS", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(2), + result_field="CITIZENSHIP_STATUS", + result_function=validators.oneOf((1, 2, 9)), + ), + ], + fields=[ + Field( + item="0", + name="RecordType", + friendly_name="record type", + type="string", + startIndex=0, + endIndex=2, + required=True, + validators=[], + ), + Field( + item="4", + name="RPT_MONTH_YEAR", + friendly_name="reporting month and year", + type="number", + startIndex=2, + endIndex=8, + required=True, + validators=[], + ), + Field( + item="6", + name="CASE_NUMBER", + friendly_name="case number", + type="string", + startIndex=8, + endIndex=19, + required=True, + validators=[validators.isAlphaNumeric()], + ), + Field( + item="66", + name="FAMILY_AFFILIATION", + friendly_name="family affiliation", + type="number", + startIndex=19, + endIndex=20, + required=True, + validators=[validators.oneOf([1, 2, 4])], + ), + Field( + item="67", + name="DATE_OF_BIRTH", + friendly_name="date of birth", + type="number", + startIndex=20, + endIndex=28, + required=True, + validators=[ + validators.dateYearIsLargerThan(1900), + validators.dateMonthIsValid(), + ], + ), + TransformField( + transform_func=tanf_ssn_decryption_func, + item="68", + name="SSN", + friendly_name="social security number - ssn", + type="string", + startIndex=28, + endIndex=37, + required=True, + validators=[validators.validateSSN()], + is_encrypted=False, + ), + Field( + item="69A", + name="RACE_HISPANIC", + friendly_name="race hispanic", + type="number", + startIndex=37, + endIndex=38, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69B", + name="RACE_AMER_INDIAN", + friendly_name="race american indian", + type="number", + startIndex=38, + endIndex=39, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69C", + name="RACE_ASIAN", + friendly_name="race asian", + type="number", + startIndex=39, + endIndex=40, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69D", + name="RACE_BLACK", + friendly_name="race black", + type="number", + startIndex=40, + endIndex=41, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69E", + name="RACE_HAWAIIAN", + friendly_name="race hawaiian", + type="number", + startIndex=41, + endIndex=42, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69F", + name="RACE_WHITE", + friendly_name="race white", + type="number", + startIndex=42, + endIndex=43, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="70", + name="GENDER", + friendly_name="gender", + type="number", + startIndex=43, + endIndex=44, + required=False, + validators=[validators.isInLimits(0, 9)], + ), + Field( + item="71A", + name="RECEIVE_NONSSA_BENEFITS", + friendly_name="receives non-social security act benefits", + type="number", + startIndex=44, + endIndex=45, + required=True, + validators=[validators.oneOf([1, 2])], + ), + Field( + item="71B", + name="RECEIVE_SSI", + friendly_name="receives social security income", + type="number", + startIndex=45, + endIndex=46, + required=True, + validators=[validators.oneOf([1, 2])], + ), + Field( + item="72", + name="RELATIONSHIP_HOH", + friendly_name="relationship to head of household", + type="string", + startIndex=46, + endIndex=48, + required=False, + validators=[validators.isInStringRange(0, 10)], + ), + Field( + item="73", + name="PARENT_MINOR_CHILD", + friendly_name="parent of minor child", + type="number", + startIndex=48, + endIndex=49, + required=False, + validators=[validators.oneOf([0, 2, 3])], + ), + Field( + item="74", + name="EDUCATION_LEVEL", + friendly_name="education level", + type="string", + startIndex=49, + endIndex=51, + required=True, + validators=[ + validators.or_validators( + validators.isInStringRange(0, 16), + validators.isInStringRange(98, 99), + ) + ], + ), + Field( + item="75", + name="CITIZENSHIP_STATUS", + friendly_name="citizenship status", + type="number", + startIndex=51, + endIndex=52, + required=False, + validators=[validators.oneOf([0, 1, 2, 9])], + ), + Field( + item="76A", + name="UNEARNED_SSI", + friendly_name="unearned ssi benefit", + type="string", + startIndex=52, + endIndex=56, + required=True, + validators=[validators.isInStringRange(0, 9999)], + ), + Field( + item="76B", + name="OTHER_UNEARNED_INCOME", + friendly_name="other unearned income", + type="string", + startIndex=56, + endIndex=60, + required=True, + validators=[validators.isInStringRange(0, 9999)], + ), + ], +) + +child_two = RowSchema( + model=Tribal_TANF_T3, + quiet_preparser_errors=True, + preparsing_validators=[ + validators.notEmpty(start=60, end=101), + validators.hasLength(122), + ], + postparsing_validators=[ + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="SSN", + result_function=validators.validateSSN(), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_HISPANIC", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_AMER_INDIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_ASIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_BLACK", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_HAWAIIAN", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RACE_WHITE", + result_function=validators.isInLimits(1, 2), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="RELATIONSHIP_HOH", + result_function=validators.isInStringRange(4, 9), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.oneOf((1, 2)), + result_field="PARENT_MINOR_CHILD", + result_function=validators.oneOf((2, 3)), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="EDUCATION_LEVEL", + result_function=validators.notMatches("99"), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(1), + result_field="CITIZENSHIP_STATUS", + result_function=validators.oneOf((1, 2)), + ), + validators.if_then_validator( + condition_field="FAMILY_AFFILIATION", + condition_function=validators.matches(2), + result_field="CITIZENSHIP_STATUS", + result_function=validators.oneOf((1, 2, 9)), + ), + ], + fields=[ + Field( + item="0", + name="RecordType", + friendly_name="record type", + type="string", + startIndex=0, + endIndex=2, + required=True, + validators=[], + ), + Field( + item="4", + name="RPT_MONTH_YEAR", + friendly_name="reporting month and year", + type="number", + startIndex=2, + endIndex=8, + required=True, + validators=[], + ), + Field( + item="6", + name="CASE_NUMBER", + friendly_name="case number", + type="string", + startIndex=8, + endIndex=19, + required=True, + validators=[validators.isAlphaNumeric()], + ), + Field( + item="66", + name="FAMILY_AFFILIATION", + friendly_name="family affiliation", + type="number", + startIndex=60, + endIndex=61, + required=True, + validators=[validators.oneOf([1, 2, 4])], + ), + Field( + item="67", + name="DATE_OF_BIRTH", + friendly_name="date of birth", + type="number", + startIndex=61, + endIndex=69, + required=True, + validators=[ + validators.dateYearIsLargerThan(1900), + validators.dateMonthIsValid(), + ], + ), + TransformField( + transform_func=tanf_ssn_decryption_func, + item="68", + name="SSN", + friendly_name="social security number - ssn", + type="string", + startIndex=69, + endIndex=78, + required=True, + validators=[validators.validateSSN()], + is_encrypted=False, + ), + Field( + item="69A", + name="RACE_HISPANIC", + friendly_name="race hispanic", + type="number", + startIndex=78, + endIndex=79, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69B", + name="RACE_AMER_INDIAN", + friendly_name="race american indian", + type="number", + startIndex=79, + endIndex=80, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69C", + name="RACE_ASIAN", + friendly_name="race asian", + type="number", + startIndex=80, + endIndex=81, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69D", + name="RACE_BLACK", + friendly_name="race black", + type="number", + startIndex=81, + endIndex=82, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69E", + name="RACE_HAWAIIAN", + friendly_name="race hawaiian", + type="number", + startIndex=82, + endIndex=83, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="69F", + name="RACE_WHITE", + friendly_name="race white", + type="number", + startIndex=83, + endIndex=84, + required=False, + validators=[validators.validateRace()], + ), + Field( + item="70", + name="GENDER", + friendly_name="gender", + type="number", + startIndex=84, + endIndex=85, + required=False, + validators=[validators.isInLimits(0, 9)], + ), + Field( + item="71A", + name="RECEIVE_NONSSA_BENEFITS", + friendly_name="receives non-ssa benefits", + type="number", + startIndex=85, + endIndex=86, + required=True, + validators=[validators.oneOf([1, 2])], + ), + Field( + item="71B", + name="RECEIVE_SSI", + friendly_name="receives SSI", + type="number", + startIndex=86, + endIndex=87, + required=True, + validators=[validators.oneOf([1, 2])], + ), + Field( + item="72", + name="RELATIONSHIP_HOH", + friendly_name="relationship to head of household", + type="string", + startIndex=87, + endIndex=89, + required=False, + validators=[validators.isInStringRange(0, 10)], + ), + Field( + item="73", + name="PARENT_MINOR_CHILD", + friendly_name="parent of minor child", + type="number", + startIndex=89, + endIndex=90, + required=False, + validators=[validators.oneOf([0, 2, 3])], + ), + Field( + item="74", + name="EDUCATION_LEVEL", + friendly_name="education level", + type="string", + startIndex=90, + endIndex=92, + required=True, + validators=[ + validators.or_validators( + validators.isInStringRange(0, 16), validators.oneOf(["98", "99"]) + ) + ], + ), + Field( + item="75", + name="CITIZENSHIP_STATUS", + friendly_name="citizenship status", + type="number", + startIndex=92, + endIndex=93, + required=False, + validators=[validators.oneOf([0, 1, 2, 9])], + ), + Field( + item="76A", + name="UNEARNED_SSI", + friendly_name="unearned ssi benefit", + type="string", + startIndex=93, + endIndex=97, + required=True, + validators=[validators.isInStringRange(0, 9999)], + ), + Field( + item="76B", + name="OTHER_UNEARNED_INCOME", + friendly_name="other unearned income", + type="string", + startIndex=97, + endIndex=101, + required=True, + validators=[validators.isInStringRange(0, 9999)], + ), + ], +) + +t3 = SchemaManager(schemas=[child_one, child_two]) diff --git a/tdrs-backend/tdpservice/parsers/test/data/ADS.E2J.FTP1.TS142 b/tdrs-backend/tdpservice/parsers/test/data/ADS.E2J.FTP1.TS142 new file mode 100644 index 000000000..c5de5c6a7 --- /dev/null +++ b/tdrs-backend/tdpservice/parsers/test/data/ADS.E2J.FTP1.TS142 @@ -0,0 +1,5 @@ +HEADER20214A00142TAN1EU +T120211011111111119255 140245112 23322 03 0 0 0 502 9 0 0 0 0 0 0 0 0 3 0222222 0 0222 12 +T2202110111111111193219690425WTTTTTZBT2222212222225 1321219 0602199 0 0 0 0 0 0 0 0 0 0 0 000 0 0 0 0 0 0 0 +T320211011111111119120100412WTTTTT9ZB212222222 63 11 0 0120140424WTTTTT@0T212222122 63981 0 0 +TRAILER0000003 diff --git a/tdrs-backend/tdpservice/parsers/test/data/tribal_section_1_inconsistency.txt b/tdrs-backend/tdpservice/parsers/test/data/tribal_section_1_inconsistency.txt new file mode 100644 index 000000000..c50875aa1 --- /dev/null +++ b/tdrs-backend/tdpservice/parsers/test/data/tribal_section_1_inconsistency.txt @@ -0,0 +1,3 @@ +HEADER20194A01142TAN1EU +T120191011111111119255 140245112 23322 03 0 0 0 502 9 0 0 0 0 0 0 0 0 3 0222222 0 0222 12 +TRAILER0000001 diff --git a/tdrs-backend/tdpservice/parsers/test/test_parse.py b/tdrs-backend/tdpservice/parsers/test/test_parse.py index 6b6a7489d..93357ae6d 100644 --- a/tdrs-backend/tdpservice/parsers/test/test_parse.py +++ b/tdrs-backend/tdpservice/parsers/test/test_parse.py @@ -5,6 +5,7 @@ from .. import parse from ..models import ParserError, ParserErrorCategoryChoices, DataFileSummary from tdpservice.search_indexes.models.tanf import TANF_T1, TANF_T2, TANF_T3, TANF_T4, TANF_T5, TANF_T6, TANF_T7 +from tdpservice.search_indexes.models.tribal import Tribal_TANF_T1, Tribal_TANF_T2, Tribal_TANF_T3 from tdpservice.search_indexes.models.ssp import SSP_M1, SSP_M2, SSP_M3, SSP_M4, SSP_M5, SSP_M6, SSP_M7 from .factories import DataFileSummaryFactory from tdpservice.data_files.models import DataFile @@ -991,3 +992,64 @@ def test_parse_ssp_section3_file(ssp_section3_file): assert first.NUM_RECIPIENTS == 51355 assert second.NUM_RECIPIENTS == 51696 assert third.NUM_RECIPIENTS == 51348 + +@pytest.fixture +def tribal_section_1_file(stt_user, stt): + """Fixture for ADS.E2J.FTP4.TS06.""" + return util.create_test_datafile('ADS.E2J.FTP1.TS142', stt_user, stt, "Tribal Active Case Data") + +@pytest.mark.django_db() +def test_parse_tribal_section_1_file(tribal_section_1_file, dfs): + """Test parsing Tribal TANF Section 1 submission.""" + tribal_section_1_file.year = 2022 + tribal_section_1_file.quarter = 'Q1' + tribal_section_1_file.save() + + dfs.datafile = tribal_section_1_file + dfs.save() + + parse.parse_datafile(tribal_section_1_file) + + dfs.status = dfs.get_status() + assert dfs.status == DataFileSummary.Status.ACCEPTED + dfs.case_aggregates = util.case_aggregates_by_month( + dfs.datafile, dfs.status) + assert dfs.case_aggregates == {'rejected': 0, + 'months': [{'month': 'Oct', 'accepted_without_errors': 1, 'accepted_with_errors': 0}, + {'month': 'Nov', 'accepted_without_errors': 0, 'accepted_with_errors': 0}, + {'month': 'Dec', 'accepted_without_errors': 0, 'accepted_with_errors': 0} + ]} + + assert Tribal_TANF_T1.objects.all().count() == 1 + assert Tribal_TANF_T2.objects.all().count() == 1 + assert Tribal_TANF_T3.objects.all().count() == 2 + + t1_objs = Tribal_TANF_T1.objects.all().order_by("CASH_AMOUNT") + t2_objs = Tribal_TANF_T2.objects.all().order_by("MONTHS_FED_TIME_LIMIT") + t3_objs = Tribal_TANF_T3.objects.all().order_by("EDUCATION_LEVEL") + + t1 = t1_objs.first() + t2 = t2_objs.first() + t3 = t3_objs.last() + + assert t1.CASH_AMOUNT == 502 + assert t2.MONTHS_FED_TIME_LIMIT == ' 0' + assert t3.EDUCATION_LEVEL == '98' + +@pytest.fixture +def tribal_section_1_inconsistency_file(stt_user, stt): + """Fixture for ADS.E2J.FTP4.TS06.""" + return util.create_test_datafile('tribal_section_1_inconsistency.txt', stt_user, stt, "Tribal Active Case Data") + +@pytest.mark.django_db() +def test_parse_tribal_section_1_inconsistency_file(tribal_section_1_inconsistency_file): + """Test parsing inconsistent Tribal TANF Section 1 submission.""" + parse.parse_datafile(tribal_section_1_inconsistency_file) + + assert Tribal_TANF_T1.objects.all().count() == 0 + + parser_errors = ParserError.objects.filter(file=tribal_section_1_inconsistency_file) + assert parser_errors.count() == 1 + + assert parser_errors.first().error_message == "Tribe Code (142) inconsistency with Program Type (TAN) " + \ + "and FIPS Code (01)." diff --git a/tdrs-backend/tdpservice/parsers/util.py b/tdrs-backend/tdpservice/parsers/util.py index 2a497e48e..685fdc59e 100644 --- a/tdrs-backend/tdpservice/parsers/util.py +++ b/tdrs-backend/tdpservice/parsers/util.py @@ -110,12 +110,6 @@ def update_encrypted_fields(self, is_encrypted): if type(field) == TransformField and "is_encrypted" in field.kwargs: field.kwargs['is_encrypted'] = is_encrypted -def contains_encrypted_indicator(line, encryption_field): - """Determine if line contains encryption indicator.""" - if encryption_field is not None: - return encryption_field.parse_value(line) == "E" - return False - def get_schema_options(program, section, query=None, model=None, model_name=None): """Centralized function to return the appropriate schema for a given program, section, and query. @@ -185,7 +179,16 @@ def get_schema_options(program, section, query=None, model=None, model_name=None } } }, - # TODO: tribal tanf + 'Tribal TAN': { + 'A': { + 'section': DataFile.Section.TRIBAL_ACTIVE_CASE_DATA, + 'models': { + 'T1': schema_defs.tribal_tanf.t1, + 'T2': schema_defs.tribal_tanf.t2, + 'T3': schema_defs.tribal_tanf.t3, + } + }, + }, } if query == "text": @@ -247,7 +250,7 @@ def get_prog_from_section(str_section): if str_section.startswith('SSP'): return 'SSP' elif str_section.startswith('Tribal'): - return 'TAN' # problematic, do we need to infer tribal entirely from tribe/fips code? + return 'Tribal TAN' else: return 'TAN' diff --git a/tdrs-backend/tdpservice/parsers/validators.py b/tdrs-backend/tdpservice/parsers/validators.py index ee86063fc..e7c2257cc 100644 --- a/tdrs-backend/tdpservice/parsers/validators.py +++ b/tdrs-backend/tdpservice/parsers/validators.py @@ -7,14 +7,16 @@ logger = logging.getLogger(__name__) -def value_is_empty(value, length): +def value_is_empty(value, length, extra_vals={}): """Handle 'empty' values as field inputs.""" - empty_values = [ + empty_values = { '', ' '*length, # ' ' '#'*length, # '#####' '_'*length, # '_____' - ] + } + + empty_values = empty_values.union(extra_vals) return value is None or value in empty_values @@ -548,3 +550,25 @@ def validate_header_section_matches_submission(datafile, section, generate_error ) return is_valid, error + +def validate_tribe_fips_program_agree(program_type, tribe_code, state_fips_code, generate_error): + """Validate tribe code, fips code, and program type all agree with eachother.""" + is_valid = False + + if program_type == 'TAN' and value_is_empty(state_fips_code, 2, extra_vals={'0'*2}): + is_valid = not value_is_empty(tribe_code, 3, extra_vals={'0'*3}) + else: + is_valid = value_is_empty(tribe_code, 3, extra_vals={'0'*3}) + + error = None + if not is_valid: + error = generate_error( + schema=None, + error_category=ParserErrorCategoryChoices.PRE_CHECK, + error_message=f"Tribe Code ({tribe_code}) inconsistency with Program Type ({program_type}) and " + + f"FIPS Code ({state_fips_code}).", + record=None, + field=None + ) + + return is_valid, error diff --git a/tdrs-backend/tdpservice/search_indexes/admin/__init__.py b/tdrs-backend/tdpservice/search_indexes/admin/__init__.py index 29e140056..8c3b3c83b 100644 --- a/tdrs-backend/tdpservice/search_indexes/admin/__init__.py +++ b/tdrs-backend/tdpservice/search_indexes/admin/__init__.py @@ -1,6 +1,6 @@ from django.contrib import admin from .. import models -from . import tanf, ssp +from . import tanf, tribal, ssp admin.site.register(models.tanf.TANF_T1, tanf.TANF_T1Admin) admin.site.register(models.tanf.TANF_T2, tanf.TANF_T2Admin) @@ -10,6 +10,10 @@ admin.site.register(models.tanf.TANF_T6, tanf.TANF_T6Admin) admin.site.register(models.tanf.TANF_T7, tanf.TANF_T7Admin) +admin.site.register(models.tribal.Tribal_TANF_T1, tribal.Tribal_TANF_T1Admin) +admin.site.register(models.tribal.Tribal_TANF_T2, tribal.Tribal_TANF_T2Admin) +admin.site.register(models.tribal.Tribal_TANF_T3, tribal.Tribal_TANF_T3Admin) + admin.site.register(models.ssp.SSP_M1, ssp.SSP_M1Admin) admin.site.register(models.ssp.SSP_M2, ssp.SSP_M2Admin) admin.site.register(models.ssp.SSP_M3, ssp.SSP_M3Admin) diff --git a/tdrs-backend/tdpservice/search_indexes/admin/tribal.py b/tdrs-backend/tdpservice/search_indexes/admin/tribal.py index dde3f9c71..71fce22b9 100644 --- a/tdrs-backend/tdpservice/search_indexes/admin/tribal.py +++ b/tdrs-backend/tdpservice/search_indexes/admin/tribal.py @@ -1 +1,56 @@ """ModelAdmin classes for parsed TRIBAL data files.""" +from django.contrib import admin +from .filter import CreationDateFilter + + +class Tribal_TANF_T1Admin(admin.ModelAdmin): + """ModelAdmin class for parsed Tribal_T1 data files.""" + + list_display = [ + 'RecordType', + 'RPT_MONTH_YEAR', + 'CASE_NUMBER', + 'COUNTY_FIPS_CODE', + 'ZIP_CODE', + 'STRATUM', + 'datafile', + ] + + list_filter = [ + CreationDateFilter, + 'RPT_MONTH_YEAR', + 'ZIP_CODE', + 'STRATUM', + ] + + +class Tribal_TANF_T2Admin(admin.ModelAdmin): + """ModelAdmin class for parsed Tribal_T2 data files.""" + + list_display = [ + 'RecordType', + 'RPT_MONTH_YEAR', + 'CASE_NUMBER', + 'datafile', + ] + + list_filter = [ + CreationDateFilter, + 'RPT_MONTH_YEAR', + ] + + +class Tribal_TANF_T3Admin(admin.ModelAdmin): + """ModelAdmin class for parsed Tribal_T3 data files.""" + + list_display = [ + 'RecordType', + 'RPT_MONTH_YEAR', + 'CASE_NUMBER', + 'datafile', + ] + + list_filter = [ + CreationDateFilter, + 'RPT_MONTH_YEAR', + ] diff --git a/tdrs-backend/tdpservice/search_indexes/documents/__init__.py b/tdrs-backend/tdpservice/search_indexes/documents/__init__.py index d430a04df..42b15a650 100644 --- a/tdrs-backend/tdpservice/search_indexes/documents/__init__.py +++ b/tdrs-backend/tdpservice/search_indexes/documents/__init__.py @@ -1,4 +1,5 @@ -from . import tanf, ssp +from . import tanf, tribal, ssp tanf = tanf +tribal = tribal ssp = ssp diff --git a/tdrs-backend/tdpservice/search_indexes/documents/tribal.py b/tdrs-backend/tdpservice/search_indexes/documents/tribal.py index 6190f9a63..e9fd193e9 100644 --- a/tdrs-backend/tdpservice/search_indexes/documents/tribal.py +++ b/tdrs-backend/tdpservice/search_indexes/documents/tribal.py @@ -1 +1,186 @@ """Elasticsearch document mappings for TRIBAL submission models.""" + +from django_elasticsearch_dsl import Document +from django_elasticsearch_dsl.registries import registry +from ..models.tribal import Tribal_TANF_T1, Tribal_TANF_T2, Tribal_TANF_T3 +from .document_base import DocumentBase + +@registry.register_document +class Tribal_TANF_T1DataSubmissionDocument(DocumentBase, Document): + """Elastic search model mapping for a parsed TANF T1 data file.""" + + class Index: + """ElasticSearch index generation settings.""" + + name = 'tribal_tanf_t1_submissions' + settings = { + 'number_of_shards': 1, + 'number_of_replicas': 0, + } + + class Django: + """Django model reference and field mapping.""" + + model = Tribal_TANF_T1 + fields = [ + 'RecordType', + 'RPT_MONTH_YEAR', + 'CASE_NUMBER', + 'COUNTY_FIPS_CODE', + 'STRATUM', + 'ZIP_CODE', + 'FUNDING_STREAM', + 'DISPOSITION', + 'NEW_APPLICANT', + 'NBR_FAMILY_MEMBERS', + 'FAMILY_TYPE', + 'RECEIVES_SUB_HOUSING', + 'RECEIVES_MED_ASSISTANCE', + 'RECEIVES_FOOD_STAMPS', + 'AMT_FOOD_STAMP_ASSISTANCE', + 'RECEIVES_SUB_CC', + 'AMT_SUB_CC', + 'CHILD_SUPPORT_AMT', + 'FAMILY_CASH_RESOURCES', + 'CASH_AMOUNT', + 'NBR_MONTHS', + 'CC_AMOUNT', + 'CHILDREN_COVERED', + 'CC_NBR_MONTHS', + 'TRANSP_AMOUNT', + 'TRANSP_NBR_MONTHS', + 'TRANSITION_SERVICES_AMOUNT', + 'TRANSITION_NBR_MONTHS', + 'OTHER_AMOUNT', + 'OTHER_NBR_MONTHS', + 'SANC_REDUCTION_AMT', + 'WORK_REQ_SANCTION', + 'FAMILY_SANC_ADULT', + 'SANC_TEEN_PARENT', + 'NON_COOPERATION_CSE', + 'FAILURE_TO_COMPLY', + 'OTHER_SANCTION', + 'RECOUPMENT_PRIOR_OVRPMT', + 'OTHER_TOTAL_REDUCTIONS', + 'FAMILY_CAP', + 'REDUCTIONS_ON_RECEIPTS', + 'OTHER_NON_SANCTION', + 'WAIVER_EVAL_CONTROL_GRPS', + 'FAMILY_EXEMPT_TIME_LIMITS', + 'FAMILY_NEW_CHILD' + ] + + +@registry.register_document +class Tribal_TANF_T2DataSubmissionDocument(DocumentBase, Document): + """Elastic search model mapping for a parsed TANF T2 data file.""" + + class Index: + """ElasticSearch index generation settings.""" + + name = 'tribal_tanf_t2_submissions' + settings = { + 'number_of_shards': 1, + 'number_of_replicas': 0, + } + + class Django: + """Django model reference and field mapping.""" + + model = Tribal_TANF_T2 + fields = [ + 'RecordType', + 'RPT_MONTH_YEAR', + 'CASE_NUMBER', + 'FAMILY_AFFILIATION', + 'NONCUSTODIAL_PARENT', + 'DATE_OF_BIRTH', + 'SSN', + 'RACE_HISPANIC', + 'RACE_AMER_INDIAN', + 'RACE_ASIAN', + 'RACE_BLACK', + 'RACE_HAWAIIAN', + 'RACE_WHITE', + 'GENDER', + 'FED_OASDI_PROGRAM', + 'FED_DISABILITY_STATUS', + 'DISABLED_TITLE_XIVAPDT', + 'AID_AGED_BLIND', + 'RECEIVE_SSI', + 'MARITAL_STATUS', + 'RELATIONSHIP_HOH', + 'PARENT_MINOR_CHILD', + 'NEEDS_PREGNANT_WOMAN', + 'EDUCATION_LEVEL', + 'CITIZENSHIP_STATUS', + 'COOPERATION_CHILD_SUPPORT', + 'MONTHS_FED_TIME_LIMIT', + 'MONTHS_STATE_TIME_LIMIT', + 'CURRENT_MONTH_STATE_EXEMPT', + 'EMPLOYMENT_STATUS', + 'WORK_PART_STATUS', + 'UNSUB_EMPLOYMENT', + 'SUB_PRIVATE_EMPLOYMENT', + 'SUB_PUBLIC_EMPLOYMENT', + 'WORK_EXPERIENCE', + 'OJT', + 'JOB_SEARCH', + 'COMM_SERVICES', + 'VOCATIONAL_ED_TRAINING', + 'JOB_SKILLS_TRAINING', + 'ED_NO_HIGH_SCHOOL_DIPLOMA', + 'SCHOOL_ATTENDENCE', + 'PROVIDE_CC', + 'ADD_WORK_ACTIVITIES', + 'OTHER_WORK_ACTIVITIES', + 'REQ_HRS_WAIVER_DEMO', + 'EARNED_INCOME', + 'UNEARNED_INCOME_TAX_CREDIT', + 'UNEARNED_SOCIAL_SECURITY', + 'UNEARNED_SSI', + 'UNEARNED_WORKERS_COMP', + 'OTHER_UNEARNED_INCOME', + ] + + +@registry.register_document +class Tribal_TANF_T3DataSubmissionDocument(DocumentBase, Document): + """Elastic search model mapping for a parsed TANF T3 data file.""" + + class Index: + """ElasticSearch index generation settings.""" + + name = 'tribal_tanf_t3_submissions' + settings = { + 'number_of_shards': 1, + 'number_of_replicas': 0, + } + + class Django: + """Django model reference and field mapping.""" + + model = Tribal_TANF_T3 + fields = [ + 'RecordType', + 'RPT_MONTH_YEAR', + 'CASE_NUMBER', + 'FAMILY_AFFILIATION', + 'DATE_OF_BIRTH', + 'SSN', + 'RACE_HISPANIC', + 'RACE_AMER_INDIAN', + 'RACE_ASIAN', + 'RACE_BLACK', + 'RACE_HAWAIIAN', + 'RACE_WHITE', + 'GENDER', + 'RECEIVE_NONSSA_BENEFITS', + 'RECEIVE_SSI', + 'RELATIONSHIP_HOH', + 'PARENT_MINOR_CHILD', + 'EDUCATION_LEVEL', + 'CITIZENSHIP_STATUS', + 'UNEARNED_SSI', + 'OTHER_UNEARNED_INCOME', + ] diff --git a/tdrs-backend/tdpservice/search_indexes/migrations/0022_tribal_tanf_t1_tribal_tanf_t2_tribal_tanf_t3.py b/tdrs-backend/tdpservice/search_indexes/migrations/0022_tribal_tanf_t1_tribal_tanf_t2_tribal_tanf_t3.py new file mode 100644 index 000000000..55211011a --- /dev/null +++ b/tdrs-backend/tdpservice/search_indexes/migrations/0022_tribal_tanf_t1_tribal_tanf_t2_tribal_tanf_t3.py @@ -0,0 +1,155 @@ +# Generated by Django 3.2.15 on 2023-10-31 16:36 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('data_files', '0012_datafile_s3_versioning_id'), + ('search_indexes', '0021_ssp_m7'), + ] + + operations = [ + migrations.CreateModel( + name='Tribal_TANF_T3', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('RecordType', models.CharField(max_length=156, null=True)), + ('RPT_MONTH_YEAR', models.IntegerField(null=True)), + ('CASE_NUMBER', models.CharField(max_length=11, null=True)), + ('FAMILY_AFFILIATION', models.IntegerField(null=True)), + ('DATE_OF_BIRTH', models.IntegerField(null=True)), + ('SSN', models.CharField(max_length=9, null=True)), + ('RACE_HISPANIC', models.IntegerField(null=True)), + ('RACE_AMER_INDIAN', models.IntegerField(null=True)), + ('RACE_ASIAN', models.IntegerField(null=True)), + ('RACE_BLACK', models.IntegerField(null=True)), + ('RACE_HAWAIIAN', models.IntegerField(null=True)), + ('RACE_WHITE', models.IntegerField(null=True)), + ('GENDER', models.IntegerField(null=True)), + ('RECEIVE_NONSSA_BENEFITS', models.IntegerField(null=True)), + ('RECEIVE_SSI', models.IntegerField(null=True)), + ('RELATIONSHIP_HOH', models.CharField(max_length=2, null=True)), + ('PARENT_MINOR_CHILD', models.IntegerField(null=True)), + ('EDUCATION_LEVEL', models.CharField(max_length=2, null=True)), + ('CITIZENSHIP_STATUS', models.IntegerField(null=True)), + ('UNEARNED_SSI', models.CharField(max_length=4, null=True)), + ('OTHER_UNEARNED_INCOME', models.CharField(max_length=4, null=True)), + ('datafile', models.ForeignKey(blank=True, help_text='The parent file from which this record was created.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tribal_t3_parent', to='data_files.datafile')), + ], + ), + migrations.CreateModel( + name='Tribal_TANF_T2', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('RecordType', models.CharField(max_length=156, null=True)), + ('RPT_MONTH_YEAR', models.IntegerField(null=True)), + ('CASE_NUMBER', models.CharField(max_length=11, null=True)), + ('FAMILY_AFFILIATION', models.IntegerField(null=True)), + ('NONCUSTODIAL_PARENT', models.IntegerField(null=True)), + ('DATE_OF_BIRTH', models.IntegerField(null=True)), + ('SSN', models.CharField(max_length=9, null=True)), + ('RACE_HISPANIC', models.IntegerField(null=True)), + ('RACE_AMER_INDIAN', models.IntegerField(null=True)), + ('RACE_ASIAN', models.IntegerField(null=True)), + ('RACE_BLACK', models.IntegerField(null=True)), + ('RACE_HAWAIIAN', models.IntegerField(null=True)), + ('RACE_WHITE', models.IntegerField(null=True)), + ('GENDER', models.IntegerField(null=True)), + ('FED_OASDI_PROGRAM', models.IntegerField(null=True)), + ('FED_DISABILITY_STATUS', models.IntegerField(null=True)), + ('DISABLED_TITLE_XIVAPDT', models.IntegerField(null=True)), + ('AID_AGED_BLIND', models.IntegerField(null=True)), + ('RECEIVE_SSI', models.IntegerField(null=True)), + ('MARITAL_STATUS', models.IntegerField(null=True)), + ('RELATIONSHIP_HOH', models.CharField(max_length=2, null=True)), + ('PARENT_MINOR_CHILD', models.IntegerField(null=True)), + ('NEEDS_PREGNANT_WOMAN', models.IntegerField(null=True)), + ('EDUCATION_LEVEL', models.CharField(max_length=2, null=True)), + ('CITIZENSHIP_STATUS', models.IntegerField(null=True)), + ('COOPERATION_CHILD_SUPPORT', models.IntegerField(null=True)), + ('MONTHS_FED_TIME_LIMIT', models.CharField(max_length=3, null=True)), + ('MONTHS_STATE_TIME_LIMIT', models.CharField(max_length=2, null=True)), + ('CURRENT_MONTH_STATE_EXEMPT', models.IntegerField(null=True)), + ('EMPLOYMENT_STATUS', models.IntegerField(null=True)), + ('WORK_PART_STATUS', models.CharField(max_length=2, null=True)), + ('UNSUB_EMPLOYMENT', models.CharField(max_length=2, null=True)), + ('SUB_PRIVATE_EMPLOYMENT', models.CharField(max_length=2, null=True)), + ('SUB_PUBLIC_EMPLOYMENT', models.CharField(max_length=2, null=True)), + ('WORK_EXPERIENCE', models.CharField(max_length=2, null=True)), + ('OJT', models.CharField(max_length=2, null=True)), + ('JOB_SEARCH', models.CharField(max_length=2, null=True)), + ('COMM_SERVICES', models.CharField(max_length=2, null=True)), + ('VOCATIONAL_ED_TRAINING', models.CharField(max_length=2, null=True)), + ('JOB_SKILLS_TRAINING', models.CharField(max_length=2, null=True)), + ('ED_NO_HIGH_SCHOOL_DIPLOMA', models.CharField(max_length=2, null=True)), + ('SCHOOL_ATTENDENCE', models.CharField(max_length=2, null=True)), + ('PROVIDE_CC', models.CharField(max_length=2, null=True)), + ('ADD_WORK_ACTIVITIES', models.CharField(max_length=2, null=True)), + ('OTHER_WORK_ACTIVITIES', models.CharField(max_length=2, null=True)), + ('REQ_HRS_WAIVER_DEMO', models.CharField(max_length=2, null=True)), + ('EARNED_INCOME', models.CharField(max_length=4, null=True)), + ('UNEARNED_INCOME_TAX_CREDIT', models.CharField(max_length=4, null=True)), + ('UNEARNED_SOCIAL_SECURITY', models.CharField(max_length=4, null=True)), + ('UNEARNED_SSI', models.CharField(max_length=4, null=True)), + ('UNEARNED_WORKERS_COMP', models.CharField(max_length=4, null=True)), + ('OTHER_UNEARNED_INCOME', models.CharField(max_length=4, null=True)), + ('datafile', models.ForeignKey(blank=True, help_text='The parent file from which this record was created.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tribal_t2_parent', to='data_files.datafile')), + ], + ), + migrations.CreateModel( + name='Tribal_TANF_T1', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('RecordType', models.CharField(max_length=156, null=True)), + ('RPT_MONTH_YEAR', models.IntegerField(null=True)), + ('CASE_NUMBER', models.CharField(max_length=11, null=True)), + ('COUNTY_FIPS_CODE', models.CharField(max_length=3, null=True)), + ('STRATUM', models.CharField(max_length=2, null=True)), + ('ZIP_CODE', models.CharField(max_length=5, null=True)), + ('FUNDING_STREAM', models.IntegerField(null=True)), + ('DISPOSITION', models.IntegerField(null=True)), + ('NEW_APPLICANT', models.IntegerField(null=True)), + ('NBR_FAMILY_MEMBERS', models.IntegerField(null=True)), + ('FAMILY_TYPE', models.IntegerField(null=True)), + ('RECEIVES_SUB_HOUSING', models.IntegerField(null=True)), + ('RECEIVES_MED_ASSISTANCE', models.IntegerField(null=True)), + ('RECEIVES_FOOD_STAMPS', models.IntegerField(null=True)), + ('AMT_FOOD_STAMP_ASSISTANCE', models.IntegerField(null=True)), + ('RECEIVES_SUB_CC', models.IntegerField(null=True)), + ('AMT_SUB_CC', models.IntegerField(null=True)), + ('CHILD_SUPPORT_AMT', models.IntegerField(null=True)), + ('FAMILY_CASH_RESOURCES', models.IntegerField(null=True)), + ('CASH_AMOUNT', models.IntegerField(null=True)), + ('NBR_MONTHS', models.IntegerField(null=True)), + ('CC_AMOUNT', models.IntegerField(null=True)), + ('CHILDREN_COVERED', models.IntegerField(null=True)), + ('CC_NBR_MONTHS', models.IntegerField(null=True)), + ('TRANSP_AMOUNT', models.IntegerField(null=True)), + ('TRANSP_NBR_MONTHS', models.IntegerField(null=True)), + ('TRANSITION_SERVICES_AMOUNT', models.IntegerField(null=True)), + ('TRANSITION_NBR_MONTHS', models.IntegerField(null=True)), + ('OTHER_AMOUNT', models.IntegerField(null=True)), + ('OTHER_NBR_MONTHS', models.IntegerField(null=True)), + ('SANC_REDUCTION_AMT', models.IntegerField(null=True)), + ('WORK_REQ_SANCTION', models.IntegerField(null=True)), + ('FAMILY_SANC_ADULT', models.IntegerField(null=True)), + ('SANC_TEEN_PARENT', models.IntegerField(null=True)), + ('NON_COOPERATION_CSE', models.IntegerField(null=True)), + ('FAILURE_TO_COMPLY', models.IntegerField(null=True)), + ('OTHER_SANCTION', models.IntegerField(null=True)), + ('RECOUPMENT_PRIOR_OVRPMT', models.IntegerField(null=True)), + ('OTHER_TOTAL_REDUCTIONS', models.IntegerField(null=True)), + ('FAMILY_CAP', models.IntegerField(null=True)), + ('REDUCTIONS_ON_RECEIPTS', models.IntegerField(null=True)), + ('OTHER_NON_SANCTION', models.IntegerField(null=True)), + ('WAIVER_EVAL_CONTROL_GRPS', models.IntegerField(null=True)), + ('FAMILY_EXEMPT_TIME_LIMITS', models.IntegerField(null=True)), + ('FAMILY_NEW_CHILD', models.IntegerField(null=True)), + ('datafile', models.ForeignKey(blank=True, help_text='The parent file from which this record was created.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tribal_t1_parent', to='data_files.datafile')), + ], + ), + ] diff --git a/tdrs-backend/tdpservice/search_indexes/models/__init__.py b/tdrs-backend/tdpservice/search_indexes/models/__init__.py index d430a04df..42b15a650 100644 --- a/tdrs-backend/tdpservice/search_indexes/models/__init__.py +++ b/tdrs-backend/tdpservice/search_indexes/models/__init__.py @@ -1,4 +1,5 @@ -from . import tanf, ssp +from . import tanf, tribal, ssp tanf = tanf +tribal = tribal ssp = ssp diff --git a/tdrs-backend/tdpservice/search_indexes/models/tribal.py b/tdrs-backend/tdpservice/search_indexes/models/tribal.py index 3aa00df34..92c328d4a 100644 --- a/tdrs-backend/tdpservice/search_indexes/models/tribal.py +++ b/tdrs-backend/tdpservice/search_indexes/models/tribal.py @@ -1 +1,189 @@ """Models representing parsed TRIBAL data file records submitted to TDP.""" + +import uuid +from django.db import models +from django.contrib.contenttypes.fields import GenericRelation +from tdpservice.data_files.models import DataFile +from tdpservice.parsers.models import ParserError + + +class Tribal_TANF_T1(models.Model): + """ + Parsed record representing a T1 data submission. + + Mapped to an elastic search index. + """ + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + datafile = models.ForeignKey( + DataFile, + blank=True, + help_text='The parent file from which this record was created.', + null=True, + on_delete=models.CASCADE, + related_name='tribal_t1_parent' + ) + + error = GenericRelation(ParserError) + RecordType = models.CharField(max_length=156, null=True, blank=False) + RPT_MONTH_YEAR = models.IntegerField(null=True, blank=False) + CASE_NUMBER = models.CharField(max_length=11, null=True, blank=False) + COUNTY_FIPS_CODE = models.CharField( + max_length=3, + null=True, + blank=False + ) + STRATUM = models.CharField(max_length=2, null=True, blank=False) + ZIP_CODE = models.CharField(max_length=5, null=True, blank=False) + FUNDING_STREAM = models.IntegerField(null=True, blank=False) + DISPOSITION = models.IntegerField(null=True, blank=False) + NEW_APPLICANT = models.IntegerField(null=True, blank=False) + NBR_FAMILY_MEMBERS = models.IntegerField(null=True, blank=False) + FAMILY_TYPE = models.IntegerField(null=True, blank=False) + RECEIVES_SUB_HOUSING = models.IntegerField(null=True, blank=False) + RECEIVES_MED_ASSISTANCE = models.IntegerField(null=True, blank=False) + RECEIVES_FOOD_STAMPS = models.IntegerField(null=True, blank=False) + AMT_FOOD_STAMP_ASSISTANCE = models.IntegerField(null=True, blank=False) + RECEIVES_SUB_CC = models.IntegerField(null=True, blank=False) + AMT_SUB_CC = models.IntegerField(null=True, blank=False) + CHILD_SUPPORT_AMT = models.IntegerField(null=True, blank=False) + FAMILY_CASH_RESOURCES = models.IntegerField(null=True, blank=False) + CASH_AMOUNT = models.IntegerField(null=True, blank=False) + NBR_MONTHS = models.IntegerField(null=True, blank=False) + CC_AMOUNT = models.IntegerField(null=True, blank=False) + CHILDREN_COVERED = models.IntegerField(null=True, blank=False) + CC_NBR_MONTHS = models.IntegerField(null=True, blank=False) + TRANSP_AMOUNT = models.IntegerField(null=True, blank=False) + TRANSP_NBR_MONTHS = models.IntegerField(null=True, blank=False) + TRANSITION_SERVICES_AMOUNT = models.IntegerField(null=True, blank=False) + TRANSITION_NBR_MONTHS = models.IntegerField(null=True, blank=False) + OTHER_AMOUNT = models.IntegerField(null=True, blank=False) + OTHER_NBR_MONTHS = models.IntegerField(null=True, blank=False) + SANC_REDUCTION_AMT = models.IntegerField(null=True, blank=False) + WORK_REQ_SANCTION = models.IntegerField(null=True, blank=False) + FAMILY_SANC_ADULT = models.IntegerField(null=True, blank=False) + SANC_TEEN_PARENT = models.IntegerField(null=True, blank=False) + NON_COOPERATION_CSE = models.IntegerField(null=True, blank=False) + FAILURE_TO_COMPLY = models.IntegerField(null=True, blank=False) + OTHER_SANCTION = models.IntegerField(null=True, blank=False) + RECOUPMENT_PRIOR_OVRPMT = models.IntegerField(null=True, blank=False) + OTHER_TOTAL_REDUCTIONS = models.IntegerField(null=True, blank=False) + FAMILY_CAP = models.IntegerField(null=True, blank=False) + REDUCTIONS_ON_RECEIPTS = models.IntegerField(null=True, blank=False) + OTHER_NON_SANCTION = models.IntegerField(null=True, blank=False) + WAIVER_EVAL_CONTROL_GRPS = models.IntegerField(null=True, blank=False) + FAMILY_EXEMPT_TIME_LIMITS = models.IntegerField(null=True, blank=False) + FAMILY_NEW_CHILD = models.IntegerField(null=True, blank=False) + + +class Tribal_TANF_T2(models.Model): + """ + Parsed record representing a T2 data submission. + + Mapped to an elastic search index. + """ + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + datafile = models.ForeignKey( + DataFile, + blank=True, + help_text='The parent file from which this record was created.', + null=True, + on_delete=models.CASCADE, + related_name='tribal_t2_parent' + ) + + RecordType = models.CharField(max_length=156, null=True, blank=False) + RPT_MONTH_YEAR = models.IntegerField(null=True, blank=False) + CASE_NUMBER = models.CharField(max_length=11, null=True, blank=False) + + FAMILY_AFFILIATION = models.IntegerField(null=True, blank=False) + NONCUSTODIAL_PARENT = models.IntegerField(null=True, blank=False) + DATE_OF_BIRTH = models.IntegerField(null=True, blank=False) + SSN = models.CharField(max_length=9, null=True, blank=False) + RACE_HISPANIC = models.IntegerField(null=True, blank=False) + RACE_AMER_INDIAN = models.IntegerField(null=True, blank=False) + RACE_ASIAN = models.IntegerField(null=True, blank=False) + RACE_BLACK = models.IntegerField(null=True, blank=False) + RACE_HAWAIIAN = models.IntegerField(null=True, blank=False) + RACE_WHITE = models.IntegerField(null=True, blank=False) + GENDER = models.IntegerField(null=True, blank=False) + FED_OASDI_PROGRAM = models.IntegerField(null=True, blank=False) + FED_DISABILITY_STATUS = models.IntegerField(null=True, blank=False) + DISABLED_TITLE_XIVAPDT = models.IntegerField(null=True, blank=False) + AID_AGED_BLIND = models.IntegerField(null=True, blank=False) + RECEIVE_SSI = models.IntegerField(null=True, blank=False) + MARITAL_STATUS = models.IntegerField(null=True, blank=False) + RELATIONSHIP_HOH = models.CharField(max_length=2, null=True, blank=False) + PARENT_MINOR_CHILD = models.IntegerField(null=True, blank=False) + NEEDS_PREGNANT_WOMAN = models.IntegerField(null=True, blank=False) + EDUCATION_LEVEL = models.CharField(max_length=2, null=True, blank=False) + CITIZENSHIP_STATUS = models.IntegerField(null=True, blank=False) + COOPERATION_CHILD_SUPPORT = models.IntegerField(null=True, blank=False) + MONTHS_FED_TIME_LIMIT = models.CharField(max_length=3, null=True, blank=False) + MONTHS_STATE_TIME_LIMIT = models.CharField(max_length=2, null=True, blank=False) + CURRENT_MONTH_STATE_EXEMPT = models.IntegerField(null=True, blank=False) + EMPLOYMENT_STATUS = models.IntegerField(null=True, blank=False) + WORK_PART_STATUS = models.CharField(max_length=2, null=True, blank=False) + UNSUB_EMPLOYMENT = models.CharField(max_length=2, null=True, blank=False) + SUB_PRIVATE_EMPLOYMENT = models.CharField(max_length=2, null=True, blank=False) + SUB_PUBLIC_EMPLOYMENT = models.CharField(max_length=2, null=True, blank=False) + WORK_EXPERIENCE = models.CharField(max_length=2, null=True, blank=False) + OJT = models.CharField(max_length=2, null=True, blank=False) + JOB_SEARCH = models.CharField(max_length=2, null=True, blank=False) + COMM_SERVICES = models.CharField(max_length=2, null=True, blank=False) + VOCATIONAL_ED_TRAINING = models.CharField(max_length=2, null=True, blank=False) + JOB_SKILLS_TRAINING = models.CharField(max_length=2, null=True, blank=False) + ED_NO_HIGH_SCHOOL_DIPLOMA = models.CharField(max_length=2, null=True, blank=False) + SCHOOL_ATTENDENCE = models.CharField(max_length=2, null=True, blank=False) + PROVIDE_CC = models.CharField(max_length=2, null=True, blank=False) + ADD_WORK_ACTIVITIES = models.CharField(max_length=2, null=True, blank=False) + OTHER_WORK_ACTIVITIES = models.CharField(max_length=2, null=True, blank=False) + REQ_HRS_WAIVER_DEMO = models.CharField(max_length=2, null=True, blank=False) + EARNED_INCOME = models.CharField(max_length=4, null=True, blank=False) + UNEARNED_INCOME_TAX_CREDIT = models.CharField(max_length=4, null=True, blank=False) + UNEARNED_SOCIAL_SECURITY = models.CharField(max_length=4, null=True, blank=False) + UNEARNED_SSI = models.CharField(max_length=4, null=True, blank=False) + UNEARNED_WORKERS_COMP = models.CharField(max_length=4, null=True, blank=False) + OTHER_UNEARNED_INCOME = models.CharField(max_length=4, null=True, blank=False) + + +class Tribal_TANF_T3(models.Model): + """ + Parsed record representing a T3 data submission. + + Mapped to an elastic search index. + """ + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + datafile = models.ForeignKey( + DataFile, + blank=True, + help_text='The parent file from which this record was created.', + null=True, + on_delete=models.CASCADE, + related_name='tribal_t3_parent' + ) + + RecordType = models.CharField(max_length=156, null=True, blank=False) + RPT_MONTH_YEAR = models.IntegerField(null=True, blank=False) + CASE_NUMBER = models.CharField(max_length=11, null=True, blank=False) + FAMILY_AFFILIATION = models.IntegerField(null=True, blank=False) + + DATE_OF_BIRTH = models.IntegerField(null=True, blank=False) + SSN = models.CharField(max_length=9, null=True, blank=False) + RACE_HISPANIC = models.IntegerField(null=True, blank=False) + RACE_AMER_INDIAN = models.IntegerField(null=True, blank=False) + RACE_ASIAN = models.IntegerField(null=True, blank=False) + RACE_BLACK = models.IntegerField(null=True, blank=False) + RACE_HAWAIIAN = models.IntegerField(null=True, blank=False) + RACE_WHITE = models.IntegerField(null=True, blank=False) + GENDER = models.IntegerField(null=True, blank=False) + RECEIVE_NONSSA_BENEFITS = models.IntegerField(null=True, blank=False) + RECEIVE_SSI = models.IntegerField(null=True, blank=False) + RELATIONSHIP_HOH = models.CharField(max_length=2, null=True, blank=False) + PARENT_MINOR_CHILD = models.IntegerField(null=True, blank=False) + EDUCATION_LEVEL = models.CharField(max_length=2, null=True, blank=False) + CITIZENSHIP_STATUS = models.IntegerField(null=True, blank=False) + UNEARNED_SSI = models.CharField(max_length=4, null=True, blank=False) + OTHER_UNEARNED_INCOME = models.CharField(max_length=4, null=True, blank=False) diff --git a/tdrs-backend/tdpservice/search_indexes/test/test_model_mapping.py b/tdrs-backend/tdpservice/search_indexes/test/test_model_mapping.py index d6089228f..28b948553 100644 --- a/tdrs-backend/tdpservice/search_indexes/test/test_model_mapping.py +++ b/tdrs-backend/tdpservice/search_indexes/test/test_model_mapping.py @@ -721,3 +721,184 @@ def test_can_create_and_index_ssp_m7_submission(test_datafile): response = search.execute() assert response.hits.total.value == 1 + +@pytest.mark.django_db +def test_can_create_and_index_tribal_tanf_t1_submission(test_datafile): + """Tribal TANF T1 submissions can be created and mapped.""" + record_num = fake.uuid4() + + submission = models.tribal.Tribal_TANF_T1() + submission.datafile = test_datafile + submission.RecordType = record_num + submission.RPT_MONTH_YEAR = 1 + submission.CASE_NUMBER = "1" + submission.COUNTY_FIPS_CODE = 1 + submission.STRATUM = "1" + submission.ZIP_CODE = "01" + submission.FUNDING_STREAM = 1 + submission.DISPOSITION = 1 + submission.NEW_APPLICANT = 1 + submission.NBR_FAMILY_MEMBERS = 1 + submission.FAMILY_TYPE = 1 + submission.RECEIVES_SUB_HOUSING = 1 + submission.RECEIVES_MED_ASSISTANCE = 1 + submission.RECEIVES_FOOD_STAMPS = 1 + submission.AMT_FOOD_STAMP_ASSISTANCE = 1 + submission.RECEIVES_SUB_CC = 1 + submission.AMT_SUB_CC = 1 + submission.CHILD_SUPPORT_AMT = 1 + submission.FAMILY_CASH_RESOURCES = 1 + submission.CASH_AMOUNT = 1 + submission.NBR_MONTHS = 1 + submission.CC_AMOUNT = 1 + submission.CHILDREN_COVERED = 1 + submission.CC_NBR_MONTHS = 1 + submission.TRANSP_AMOUNT = 1 + submission.TRANSP_NBR_MONTHS = 1 + submission.TRANSITION_SERVICES_AMOUNT = 1 + submission.TRANSITION_NBR_MONTHS = 1 + submission.OTHER_AMOUNT = 1 + submission.OTHER_NBR_MONTHS = 1 + submission.SANC_REDUCTION_AMT = 1 + submission.WORK_REQ_SANCTION = 1 + submission.FAMILY_SANC_ADULT = 1 + submission.SANC_TEEN_PARENT = 1 + submission.NON_COOPERATION_CSE = 1 + submission.FAILURE_TO_COMPLY = 1 + submission.OTHER_SANCTION = 1 + submission.RECOUPMENT_PRIOR_OVRPMT = 1 + submission.OTHER_TOTAL_REDUCTIONS = 1 + submission.FAMILY_CAP = 1 + submission.REDUCTIONS_ON_RECEIPTS = 1 + submission.OTHER_NON_SANCTION = 1 + submission.WAIVER_EVAL_CONTROL_GRPS = 1 + submission.FAMILY_EXEMPT_TIME_LIMITS = 1 + submission.FAMILY_NEW_CHILD = 1 + + submission.save() + + # submission.full_clean() + + assert submission.id is not None + + search = documents.tribal.Tribal_TANF_T1DataSubmissionDocument.search().query( + 'match', + RecordType=record_num + ) + response = search.execute() + + assert response.hits.total.value == 1 + + +@pytest.mark.django_db +def test_can_create_and_index_tribal_tanf_t2_submission(test_datafile): + """Tribal TANF T2 submissions can be created and mapped.""" + record_num = fake.uuid4() + + submission = models.tribal.Tribal_TANF_T2() + submission.datafile = test_datafile + submission.RecordType = record_num + submission.RPT_MONTH_YEAR = 1 + submission.CASE_NUMBER = '1' + submission.FAMILY_AFFILIATION = 1 + submission.NONCUSTODIAL_PARENT = 1 + submission.DATE_OF_BIRTH = 1 + submission.SSN = '1' + submission.RACE_HISPANIC = 1 + submission.RACE_AMER_INDIAN = 1 + submission.RACE_ASIAN = 1 + submission.RACE_BLACK = 1 + submission.RACE_HAWAIIAN = 1 + submission.RACE_WHITE = 1 + submission.GENDER = 1 + submission.FED_OASDI_PROGRAM = 1 + submission.FED_DISABILITY_STATUS = 1 + submission.DISABLED_TITLE_XIVAPDT = 1 + submission.AID_AGED_BLIND = 1 + submission.RECEIVE_SSI = 1 + submission.MARITAL_STATUS = 1 + submission.RELATIONSHIP_HOH = "01" + submission.NEEDS_PREGNANT_WOMAN = 1 + submission.EDUCATION_LEVEL = 1 + submission.CITIZENSHIP_STATUS = 1 + submission.COOPERATION_CHILD_SUPPORT = 1 + submission.MONTHS_FED_TIME_LIMIT = 1 + submission.MONTHS_STATE_TIME_LIMIT = 1 + submission.CURRENT_MONTH_STATE_EXEMPT = 1 + submission.EMPLOYMENT_STATUS = 1 + submission.WORK_PART_STATUS = 1 + submission.UNSUB_EMPLOYMENT = 1 + submission.SUB_PRIVATE_EMPLOYMENT = 1 + submission.SUB_PUBLIC_EMPLOYMENT = 1 + submission.WORK_EXPERIENCE = 1 + submission.OJT = 1 + submission.JOB_SEARCH = 1 + submission.COMM_SERVICES = 1 + submission.VOCATIONAL_ED_TRAINING = 1 + submission.JOB_SKILLS_TRAINING = 1 + submission.ED_NO_HIGH_SCHOOL_DIPLOMA = 1 + submission.SCHOOL_ATTENDENCE = 1 + submission.PROVIDE_CC = 1 + submission.ADD_WORK_ACTIVITIES = '01' + submission.OTHER_WORK_ACTIVITIES = 1 + submission.REQ_HRS_WAIVER_DEMO = 1 + submission.EARNED_INCOME = 1 + submission.UNEARNED_INCOME_TAX_CREDIT = 1 + submission.UNEARNED_SOCIAL_SECURITY = 1 + submission.UNEARNED_SSI = 1 + submission.UNEARNED_WORKERS_COMP = 1 + submission.OTHER_UNEARNED_INCOME = 1 + + submission.save() + + assert submission.id is not None + + search = documents.tribal.Tribal_TANF_T2DataSubmissionDocument.search().query( + 'match', + RecordType=record_num + ) + response = search.execute() + + assert response.hits.total.value == 1 + + +@pytest.mark.django_db +def test_can_create_and_index_tribal_tanf_t3_submission(test_datafile): + """Tribal TANF T3 submissions can be created and mapped.""" + record_num = fake.uuid4() + + submission = models.tribal.Tribal_TANF_T3() + submission.datafile = test_datafile + submission.RecordType = record_num + submission.RPT_MONTH_YEAR = 1 + submission.CASE_NUMBER = '1' + submission.FAMILY_AFFILIATION = 1 + submission.DATE_OF_BIRTH = 1 + submission.SSN = '1' + submission.RACE_HISPANIC = 1 + submission.RACE_AMER_INDIAN = 1 + submission.RACE_ASIAN = 1 + submission.RACE_BLACK = 1 + submission.RACE_HAWAIIAN = 1 + submission.RACE_WHITE = 1 + submission.GENDER = 1 + submission.RECEIVE_NONSSA_BENEFITS = 1 + submission.RECEIVE_SSI = 1 + submission.RELATIONSHIP_HOH = "01" + submission.PARENT_MINOR_CHILD = 1 + submission.EDUCATION_LEVEL = 1 + submission.CITIZENSHIP_STATUS = 1 + submission.UNEARNED_SSI = 1 + submission.OTHER_UNEARNED_INCOME = 1 + + submission.save() + + assert submission.id is not None + + search = documents.tribal.Tribal_TANF_T3DataSubmissionDocument.search().query( + 'match', + RecordType=record_num + ) + response = search.execute() + + assert response.hits.total.value == 1 diff --git a/tdrs-backend/tdpservice/users/test/test_permissions.py b/tdrs-backend/tdpservice/users/test/test_permissions.py index 4ac21409a..a96897e94 100644 --- a/tdrs-backend/tdpservice/users/test/test_permissions.py +++ b/tdrs-backend/tdpservice/users/test/test_permissions.py @@ -135,6 +135,15 @@ def test_ofa_system_admin_permissions(ofa_system_admin): 'search_indexes.add_ssp_m7', 'search_indexes.view_ssp_m7', 'search_indexes.change_ssp_m7', + 'search_indexes.add_tribal_tanf_t1', + 'search_indexes.view_tribal_tanf_t1', + 'search_indexes.change_tribal_tanf_t1', + 'search_indexes.add_tribal_tanf_t2', + 'search_indexes.view_tribal_tanf_t2', + 'search_indexes.change_tribal_tanf_t2', + 'search_indexes.add_tribal_tanf_t3', + 'search_indexes.view_tribal_tanf_t3', + 'search_indexes.change_tribal_tanf_t3', } group_permissions = ofa_system_admin.get_group_permissions() assert group_permissions == expected_permissions