def test_failure(database): """ PrimaryPlaceOfPerformanceCountryCode must contain a valid three character GENC country code for aggregate or non-aggregate records (RecordType = 1 or 2). U.S. Territories and Freely Associated States must be submitted with country code = USA and their state/territory code; they cannot be submitted with their GENC country code. """ cc_1 = CountryCode(country_code='ASM', country_name='AMERICAN SAMOA', territory_free_state=True) fabs = FABSFactory(place_of_perform_country_c='xyz', record_type=1, correction_delete_indicatr='') fabs_2 = FABSFactory(place_of_perform_country_c='ABCD', record_type=2, correction_delete_indicatr=None) fabs_3 = FABSFactory(place_of_perform_country_c='', record_type=2, correction_delete_indicatr='c') fabs_4 = FABSFactory(place_of_perform_country_c='ASM', record_type=1, correction_delete_indicatr='C') errors = number_of_errors(_FILE, database, models=[cc_1, fabs, fabs_2, fabs_3, fabs_4]) assert errors == 4
def test_failure(database): """ Test failure when LegalEntityZIP5 is blank for domestic recipients for non-aggregate and PII-redacted non-aggregate records """ fabs = FABSFactory(legal_entity_country_code='USA', record_type=2, legal_entity_zip5=None, correction_delete_indicatr='') fabs_2 = FABSFactory(legal_entity_country_code='UsA', record_type=2, legal_entity_zip5='', correction_delete_indicatr='C') fabs_3 = FABSFactory(legal_entity_country_code='USA', record_type=3, legal_entity_zip5=None, correction_delete_indicatr='') fabs_4 = FABSFactory(legal_entity_country_code='USA', record_type=3, legal_entity_zip5='', correction_delete_indicatr='') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2, fabs_3, fabs_4]) assert errors == 4
def test_failure(database): """ Test failure for when provided, PrimaryPlaceofPerformanceZIP+4 must be in the state specified by PrimaryPlaceOfPerformanceCode. In this specific submission row, the ZIP5 (and by extension the full ZIP+4) is not a valid ZIP code in the state in question. """ zips = Zips(zip5='12345', zip_last4='6789', state_abbreviation='NY') # invalid 5 digit zip fabs_1 = FABSFactory(place_of_performance_code='ny10986', place_of_performance_zip4a='12346', correction_delete_indicatr='') fabs_2 = FABSFactory(place_of_performance_code='NA*****', place_of_performance_zip4a='12345', correction_delete_indicatr='c') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, zips]) assert errors == 2 # invalid 9 digit zip - first five fail (see d41_5 for the last four to fail) fabs_1 = FABSFactory(place_of_performance_code='ny10986', place_of_performance_zip4a='123466789', correction_delete_indicatr=None) fabs_2 = FABSFactory(place_of_performance_code='NY*****', place_of_performance_zip4a='12346-6789', correction_delete_indicatr='C') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, zips]) assert errors == 2
def test_success(database): """ Test FundingOpportunityGoalsText must be blank for non-grants/non-cooperative agreements (AssistanceType = 06, 07, 08, 09, 10, or 11). """ fabs_1 = FABSFactory(funding_opportunity_goals='', assistance_type='06', correction_delete_indicatr='C') fabs_2 = FABSFactory(funding_opportunity_goals=None, assistance_type='09', correction_delete_indicatr=None) # Ignored for other assistance types fabs_3 = FABSFactory(funding_opportunity_goals='123', assistance_type='03', correction_delete_indicatr='C') # Ignored for CorrectionDeleteIndicator of D fabs_4 = FABSFactory(funding_opportunity_goals='123', assistance_type='08', correction_delete_indicatr='d') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3, fabs_4]) assert errors == 0
def test_failure(database): """ The unique combination of FAIN, AwardModificationAmendmentNumber, URI, CFDA_Number, and AwardingSubTierAgencyCode must exist as a currently published record when the record is a deletion (i.e., if CorrectionDeleteIndicator = D). Ignore all other CorrectionDeleteIndicators in this rule. """ fabs_1 = FABSFactory(afa_generated_unique='ama1asta1fain2uri1', correction_delete_indicatr='D') # Test that capitalization differences don't affect the error fabs_2 = FABSFactory(afa_generated_unique='amA1astA1fain2uRi1', correction_delete_indicatr='D') pub_fabs_1 = PublishedFABSFactory( afa_generated_unique='ama1asta1fain1uri1', correction_delete_indicatr=None, is_active=True) pub_fabs_2 = PublishedFABSFactory( afa_generated_unique='ama1asta1fAin2uri1', correction_delete_indicatr=None, is_active=False) errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, pub_fabs_1, pub_fabs_2]) assert errors == 2
def test_failure(database): """ Test invalid. For new (ActionType = A) or mixed aggregate (ActionType = E) assistance awards specifically, the CFDA_Number must be active as of the ActionDate. This does not apply to correction records (those with CorrectionDeleteIndicator = C and delete records). """ cfda = CFDAProgram(program_number=12.340, published_date='20130427', archived_date='') fabs_1 = FABSFactory(cfda_number='12.340', action_date='20120111', action_type='e', correction_delete_indicatr='B') fabs_2 = FABSFactory(cfda_number='12.340', action_date='20120111', action_type='A', correction_delete_indicatr=None) fabs_3 = FABSFactory(cfda_number='12.340', action_date='20120111', action_type='a', correction_delete_indicatr='B') fabs_4 = FABSFactory(cfda_number='12.340', action_date='20120111', action_type='E', correction_delete_indicatr=None) errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3, fabs_4, cfda]) assert errors == 4
def test_success(database): """ AwardingSubTierAgencyCode must be provided when AwardingOfficeCode is not provided. """ # Missing office code, has sub tier code fabs_1 = FABSFactory(awarding_sub_tier_agency_c='000', awarding_office_code='', correction_delete_indicatr='') # Both codes present fabs_2 = FABSFactory(awarding_sub_tier_agency_c='000', awarding_office_code='0000', correction_delete_indicatr=None) # Missing sub tier code, has office code fabs_3 = FABSFactory(awarding_sub_tier_agency_c=None, awarding_office_code='0000', correction_delete_indicatr='c') # Ignore correction delete indicator of D fabs_4 = FABSFactory(awarding_sub_tier_agency_c='', awarding_office_code='', correction_delete_indicatr='d') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3, fabs_4]) assert errors == 0
def test_pubished_date_failure(database): """ Test failure for when provided, AwardeeOrRecipientUEI must be registered (not necessarily active) in SAM, unless the ActionDate is before October 1, 2010. """ pub_fabs_1 = PublishedFABSFactory(unique_award_key='active_key', action_date='20220404', is_active=True) pub_fabs_2 = PublishedFABSFactory(unique_award_key='inactive_key', action_date='20091001', is_active=False) models = [pub_fabs_1, pub_fabs_2] # new records that may or may not be related to older awards recipient = SAMRecipient(uei='1111111111111E') fabs_1 = FABSFactory(uei='12345', assistance_type='02', action_date='10/02/2010', correction_delete_indicatr='', unique_award_key='active_key') fabs_2 = FABSFactory(uei='12345', assistance_type='06', action_date='04/05/2022', correction_delete_indicatr=None, unique_award_key='inactive_key') models += [recipient, fabs_1, fabs_2] errors = number_of_errors(_FILE, database, models=models) assert errors == 2
def test_failure(database): """ Fail ActionType should be "A" for the initial transaction of a new, non-aggregate award (RecordType = 2 or 3) and “A” or “E” for a new aggregate award (RecordType = 1). An aggregate record transaction is considered the initial transaction of a new award if it contains a unique combination of URI + AwardingSubTierAgencyCode when compared to currently published FABS records of the same RecordType. A non-aggregate (RecordType = 2 or 3) transaction is considered the initial transaction of a new award if it contains a unique combination of FAIN + AwardingSubTierAgencyCode when compared to currently published non-aggregate FABS records (RecordType = 2 or 3) of the same RecordType. """ fabs_1 = FABSFactory(unique_award_key='unique1', action_type='b', record_type=1, correction_delete_indicatr=None) # E is only valid for record type 1 fabs_2 = FABSFactory(unique_award_key='unique2', action_type='E', record_type=2, correction_delete_indicatr='') pub_fabs_1 = PublishedFABSFactory(unique_award_key='unique2', is_active=False) errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, pub_fabs_1]) assert errors == 2
def test_success(database): """ Test success LegalEntityForeignCityName must be blank for domestic recipients (LegalEntityCountryCode = USA) and for aggregate records (RecordType = 1). """ fabs = FABSFactory(legal_entity_country_code='UsA', legal_entity_foreign_city=None, record_type=2, correction_delete_indicatr='') fabs_2 = FABSFactory(legal_entity_country_code='USA', legal_entity_foreign_city='', record_type=3, correction_delete_indicatr=None) fabs_3 = FABSFactory(legal_entity_country_code='UKR', legal_entity_foreign_city='', record_type=1, correction_delete_indicatr='c') # Ignore correction delete indicator of D fabs_4 = FABSFactory(legal_entity_country_code='UKR', legal_entity_foreign_city='Test City', record_type=1, correction_delete_indicatr='d') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2, fabs_3, fabs_4]) assert errors == 0
def test_failure(database): """ BusinessTypes must be one to three letters in length. BusinessTypes values must be non-repeated letters from A to X. """ # Test if it's somehow empty or has 4 letters (length test) fabs = FABSFactory(business_types='', correction_delete_indicatr='') fabs_2 = FABSFactory(business_types='ABCD', correction_delete_indicatr='c') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2]) assert errors == 2 # Test repeats fabs = FABSFactory(business_types='BOb', correction_delete_indicatr='') fabs_2 = FABSFactory(business_types='BOB', correction_delete_indicatr='c') fabs_3 = FABSFactory(business_types='BbO', correction_delete_indicatr='') fabs_4 = FABSFactory(business_types='BB', correction_delete_indicatr='') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2, fabs_3, fabs_4]) assert errors == 4 # Test that only valid letters work fabs = FABSFactory(business_types='ABY', correction_delete_indicatr='') fabs_2 = FABSFactory(business_types='C2', correction_delete_indicatr='c') fabs_3 = FABSFactory(business_types='c2d', correction_delete_indicatr='') fabs_4 = FABSFactory(business_types='123', correction_delete_indicatr='') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2, fabs_3, fabs_4]) assert errors == 4
def test_failure(database): """ Tests URI is not required field for non-aggregate records (i.e., when RecordType != 1). """ fabs_1 = FABSFactory(record_type=1, uri=None, correction_delete_indicatr='') fabs_2 = FABSFactory(record_type=1, uri='', correction_delete_indicatr='C') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2]) assert errors == 2
def test_pubished_date_failure(database): """ Test failure for when ActionDate is after October 1, 2010 and ActionType = B, C, or D, AwardeeOrRecipientUEI should (when provided) have an active registration in SAM as of the ActionDate, except where FederalActionObligation is <=0 and ActionType = D. """ recipient = SAMRecipient(uei='11111111111E', registration_date='01/01/2017', expiration_date='01/01/2018') fabs_1 = FABSFactory(uei='12345', action_type='b', action_date='06/20/2020', federal_action_obligation=10, correction_delete_indicatr='') # FOA <= 0 and ActionType D checks individually fabs_2 = FABSFactory(uei='12345', action_type='d', action_date='06/20/2020', federal_action_obligation=1, correction_delete_indicatr='') fabs_3 = FABSFactory(uei='12345', action_type='b', action_date='06/20/2020', federal_action_obligation=0, correction_delete_indicatr='') errors = number_of_errors(_FILE, database, models=[recipient, fabs_1, fabs_2, fabs_3]) assert errors == 3
def test_pubished_date_success(database): """ Test success for when ActionDate is after October 1, 2010 and ActionType = A, AwardeeOrRecipientUEI should (when provided) have an active registration in SAM as of the ActionDate. """ recipient = SAMRecipient(uei='11111111111E', registration_date='01/01/2017', expiration_date='01/01/2018') fabs_1 = FABSFactory(uei=recipient.uei, action_type='a', action_date='06/22/2017', correction_delete_indicatr='') # Ignore different action type fabs_2 = FABSFactory(uei='12345', action_type='B', action_date='06/20/2019', correction_delete_indicatr='') # Ignore Before October 1, 2010 fabs_3 = FABSFactory(uei='12345', action_type='a', action_date='09/30/2010', correction_delete_indicatr=None) # Ignore correction delete indicator of D fabs_4 = FABSFactory(uei='12345', action_type='A', action_date='06/20/2020', correction_delete_indicatr='d') errors = number_of_errors( _FILE, database, models=[recipient, fabs_1, fabs_2, fabs_3, fabs_4]) assert errors == 0
def test_success(database): """ PrimaryPlaceOfPerformanceCountryCode must contain a valid three character GENC country code for aggregate or non-aggregate records (RecordType = 1 or 2). U.S. Territories and Freely Associated States must be submitted with country code = USA and their state/territory code; they cannot be submitted with their GENC country code. """ cc_1 = CountryCode(country_code='USA', country_name='United States', territory_free_state=False) cc_2 = CountryCode(country_code='UKR', country_name='Ukraine', territory_free_state=False) fabs = FABSFactory(place_of_perform_country_c='USA', record_type=1, correction_delete_indicatr='') fabs_2 = FABSFactory(place_of_perform_country_c='uKr', record_type=2, correction_delete_indicatr='C') fabs_3 = FABSFactory(place_of_perform_country_c='abc', record_type=3, correction_delete_indicatr=None) # Ignore correction delete indicator of D fabs_4 = FABSFactory(place_of_perform_country_c='xyz', record_type=1, correction_delete_indicatr='d') errors = number_of_errors( _FILE, database, models=[cc_1, cc_2, fabs, fabs_2, fabs_3, fabs_4]) assert errors == 0
def test_failure(database): """ Test failure for when AwardeeOrRecipientUEI is provided, it must be twelve characters. """ fabs_1 = FABSFactory(uei='2', correction_delete_indicatr='') fabs_2 = FABSFactory(uei='1234567s89aBc', correction_delete_indicatr='c') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2]) assert errors == 2
def test_failure(database): """ Tests failure for when Record type is required and cannot be blank. It must be 1, 2, or 3 """ fabs_1 = FABSFactory(record_type=0, correction_delete_indicatr=None) fabs_2 = FABSFactory(record_type=None, correction_delete_indicatr='c') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2]) assert errors == 2
def test_failure(database): """ Test failure if LegalEntityZIPLast4 is not provided and LegalEntityZIP5 is, LegalEntityCongressionalDistrict must be provided or domestic and non-aggregate and PII-redacted non-aggregate records (RecordType = 2 or 3) """ fabs_1 = FABSFactory(legal_entity_zip5='12345', legal_entity_zip_last4='', legal_entity_congressional='', legal_entity_country_code='USA', record_type=2, correction_delete_indicatr='') fabs_2 = FABSFactory(legal_entity_zip5='12345', legal_entity_zip_last4=None, legal_entity_congressional='', legal_entity_country_code='usa', record_type=3, correction_delete_indicatr='C') fabs_3 = FABSFactory(legal_entity_zip5='12345', legal_entity_zip_last4='', legal_entity_congressional=None, legal_entity_country_code='USA', record_type=2, correction_delete_indicatr='c') fabs_4 = FABSFactory(legal_entity_zip5='12345', legal_entity_zip_last4=None, legal_entity_congressional=None, legal_entity_country_code='usa', record_type=3, correction_delete_indicatr=None) errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3, fabs_4]) assert errors == 4
def test_success(database): """ ActionType = E is only valid for mixed aggregate records (RecordType = 1.) """ fabs_1 = FABSFactory(record_type=1, action_type='E', correction_delete_indicatr=None) fabs_2 = FABSFactory(record_type=1, action_type='e', correction_delete_indicatr='C') # Ignore delete record fabs_3 = FABSFactory(record_type=2, action_type='e', correction_delete_indicatr='D') # Can have whatever we want for other record types for this rule fabs_4 = FABSFactory(record_type=2, action_type='a', correction_delete_indicatr='') # Can have whatever other action type we want for record type 1 fabs_5 = FABSFactory(record_type=1, action_type='a', correction_delete_indicatr='') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3, fabs_4, fabs_5]) assert errors == 0
def test_success(database): """ Test IndirectCostFederalShareAmount is required for grants and cooperative agreements (AssistanceType = 02, 03, 04, or 05). This only applies to award actions with ActionDate on or after April 4, 2022. """ fabs_1 = FABSFactory(indirect_federal_sharing=123, assistance_type='02', action_date='05/05/2022') # Doesn't care about other assistance types fabs_2 = FABSFactory(indirect_federal_sharing=None, assistance_type='09', action_date='05/05/2022') # Doesn't care about earlier dates fabs_3 = FABSFactory(indirect_federal_sharing=None, assistance_type='03', action_date='05/05/2021') # Still doesn't trigger when not blank for other assistance types fabs_4 = FABSFactory(indirect_federal_sharing=123, assistance_type='09') # Ignore when CorrectionDeleteIndicator is D fabs_5 = FABSFactory(indirect_federal_sharing=123, assistance_type='09', correction_delete_indicatr='d') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3, fabs_4, fabs_5]) assert errors == 0
def test_failure(database): """ Test fail BusinessFundsIndicator is required for all submissions except delete records. """ fabs = FABSFactory(correction_delete_indicatr='c', business_funds_indicator=None) fabs_2 = FABSFactory(correction_delete_indicatr=None, business_funds_indicator='') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2]) assert errors == 2
def test_failure(database): """ Test fail ActionType is required for all submissions except delete records. """ fabs = FABSFactory(correction_delete_indicatr='c', action_type=None) fabs_2 = FABSFactory(correction_delete_indicatr=None, action_type='') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2]) assert errors == 2
def test_failure(database): """ Test fail AwardeeOrRecipientLegalEntityName is required for all submissions except delete records. """ fabs = FABSFactory(correction_delete_indicatr='c', awardee_or_recipient_legal=None) fabs_2 = FABSFactory(correction_delete_indicatr=None, awardee_or_recipient_legal='') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2]) assert errors == 2
def test_failure(database): """ Tests if ActionType is not one of the following values: “A”, “B”, “C”, “D”, or "E". """ fabs_1 = FABSFactory(action_type='random', correction_delete_indicatr='c') fabs_2 = FABSFactory(action_type='', correction_delete_indicatr='') fabs_3 = FABSFactory(action_type=None, correction_delete_indicatr='C') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3]) assert errors == 3
def test_failure(database): """ When provided, PeriodOfPerformanceCurrentEndDate must be a valid date between 19991001 and 20991231. (i.e., a date between 10/01/1999 and 12/31/2099) """ fabs_1 = FABSFactory(period_of_performance_curr='19990131', correction_delete_indicatr='c') fabs_2 = FABSFactory(period_of_performance_curr='21000101', correction_delete_indicatr=None) errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2]) assert errors == 2
def test_failure(database): """ When provided, LegalEntityZIPLast4 must be in the format ####. """ fabs_1 = FABSFactory(legal_entity_zip_last4='123', correction_delete_indicatr='') fabs_2 = FABSFactory(legal_entity_zip_last4='12345', correction_delete_indicatr=None) fabs_3 = FABSFactory(legal_entity_zip_last4='ABCD', correction_delete_indicatr='c') fabs_4 = FABSFactory(legal_entity_zip_last4='123D', correction_delete_indicatr='C') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3, fabs_4]) assert errors == 4
def test_failure(database): """ Test fail LegalEntityCountryCode is required for all submissions except delete records. """ fabs = FABSFactory(correction_delete_indicatr='c', legal_entity_country_code=None) fabs_2 = FABSFactory(correction_delete_indicatr=None, legal_entity_country_code='') errors = number_of_errors(_FILE, database, models=[fabs, fabs_2]) assert errors == 2
def test_failure(database): """ Tests failure for when AssistanceType field is required and must be one of the allowed values: '02', '03', '04', '05', '06', '07', '08', '09', '10', '11' """ fabs_1 = FABSFactory(assistance_type='', correction_delete_indicatr='') fabs_2 = FABSFactory(assistance_type=None, correction_delete_indicatr=None) fabs_3 = FABSFactory(assistance_type='random', correction_delete_indicatr='c') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3]) assert errors == 3
def test_success(database): """ Test valid. CFDA_Number must be in XX.XXX format """ fabs_1 = FABSFactory(cfda_number='99.999', correction_delete_indicatr='') fabs_2 = FABSFactory(cfda_number='12.345', correction_delete_indicatr='c') # Ignore correction delete indicator of D fabs_3 = FABSFactory(cfda_number='1234', correction_delete_indicatr='d') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, fabs_3]) assert errors == 0
def test_success(database): """ Test that no errors occur when the cfda_number exists. """ cfda = CFDAProgram(program_number=12.340) fabs_1 = FABSFactory(cfda_number='12.340', correction_delete_indicatr='') # Ignore correction delete indicator of D fabs_2 = FABSFactory(cfda_number='AB.CDE', correction_delete_indicatr='d') errors = number_of_errors(_FILE, database, models=[fabs_1, fabs_2, cfda]) assert errors == 0