From 826167b1e4142f6723177a161e60858053a99c16 Mon Sep 17 00:00:00 2001 From: "Hassan D. M. Sambo" Date: Tue, 11 Jun 2024 13:55:09 -0400 Subject: [PATCH 1/4] 3928 address historical report with empty award boolean fields (#3929) * #3928 Updated logic to handle award with missing boolean values * #3928 Updated schema to allow gsa_migration for missing boolean --- .../checks/check_gsa_migration_keyword.py | 1 + .../sac_general_lib/audit_information.py | 7 +- .../test_federal_awards_xforms.py | 61 +++++++++++++++++ .../workbooklib/federal_awards.py | 65 ++++++++++++++++++- .../output/sections/FederalAwards.schema.json | 3 +- .../sections/FederalAwards.schema.jsonnet | 2 +- 6 files changed, 134 insertions(+), 5 deletions(-) diff --git a/backend/audit/intakelib/checks/check_gsa_migration_keyword.py b/backend/audit/intakelib/checks/check_gsa_migration_keyword.py index be43a78e66..2a4a5e4140 100644 --- a/backend/audit/intakelib/checks/check_gsa_migration_keyword.py +++ b/backend/audit/intakelib/checks/check_gsa_migration_keyword.py @@ -44,6 +44,7 @@ def check_for_gsa_migration_keyword(ir): "material_weakness", "significant_deficiency", "repeat_prior_reference", + "is_guaranteed", ] for range_name in range_names: diff --git a/backend/census_historical_migration/sac_general_lib/audit_information.py b/backend/census_historical_migration/sac_general_lib/audit_information.py index a8c13fd6ac..3e0d2a0d1e 100644 --- a/backend/census_historical_migration/sac_general_lib/audit_information.py +++ b/backend/census_historical_migration/sac_general_lib/audit_information.py @@ -75,7 +75,12 @@ def _get_agency_prefixes(dbkey, year): audits = get_audits(dbkey, year) for audit_detail in audits: - agencies.add(string_to_string(audit_detail.CFDA_PREFIX)) + prefix = ( + string_to_string(audit_detail.CFDA_PREFIX) + if audit_detail.CFDA_PREFIX + else string_to_string(audit_detail.CFDA).split(".")[0] + ) + agencies.add(prefix) return agencies diff --git a/backend/census_historical_migration/test_federal_awards_xforms.py b/backend/census_historical_migration/test_federal_awards_xforms.py index e4d01d3bd4..326b738540 100644 --- a/backend/census_historical_migration/test_federal_awards_xforms.py +++ b/backend/census_historical_migration/test_federal_awards_xforms.py @@ -27,6 +27,8 @@ xform_missing_major_program, is_valid_extension, xform_cluster_names, + xform_replace_missing_prefix, + xform_replace_required_values_with_gsa_migration_when_empty, xform_sanitize_additional_award_identification, ) @@ -851,3 +853,62 @@ def test_no_invalid_federal_program_total(self): InvalidRecord.fields["validations_to_skip"], ) self.assertNotIn + + +class TestXformMissingPrefix(SimpleTestCase): + class MockAudit: + + def __init__(self, CFDA_PREFIX, CFDA): + self.CFDA_PREFIX = CFDA_PREFIX + self.CFDA = CFDA + + def test_for_no_missing_prefix(self): + """Test for no missing prefix""" + audits = [self.MockAudit("01", "01.123"), self.MockAudit("02", "02.456")] + + xform_replace_missing_prefix(audits) + + self.assertEqual(audits[0].CFDA_PREFIX, "01") + self.assertEqual(audits[1].CFDA_PREFIX, "02") + + def test_for_missing_prefix(self): + """Test for missing prefix""" + audits = [self.MockAudit("", "01.123"), self.MockAudit("02", "02.456")] + + xform_replace_missing_prefix(audits) + + self.assertEqual(audits[0].CFDA_PREFIX, "01") + self.assertEqual(audits[1].CFDA_PREFIX, "02") + + +class TestXformReplaceMissingFields(SimpleTestCase): + + class MockAudit: + + def __init__( + self, + LOANS, + DIRECT, + ): + self.LOANS = LOANS + self.DIRECT = DIRECT + + def test_replace_empty_fields(self): + audits = [ + self.MockAudit( + LOANS="", + DIRECT="", + ), + self.MockAudit( + LOANS="Present", + DIRECT="Present", + ), + ] + + xform_replace_required_values_with_gsa_migration_when_empty(audits) + + self.assertEqual(audits[0].LOANS, settings.GSA_MIGRATION) + self.assertEqual(audits[0].DIRECT, settings.GSA_MIGRATION) + + self.assertEqual(audits[1].LOANS, "Present") + self.assertEqual(audits[1].DIRECT, "Present") diff --git a/backend/census_historical_migration/workbooklib/federal_awards.py b/backend/census_historical_migration/workbooklib/federal_awards.py index addc6af64a..40af1d467a 100644 --- a/backend/census_historical_migration/workbooklib/federal_awards.py +++ b/backend/census_historical_migration/workbooklib/federal_awards.py @@ -451,6 +451,32 @@ def is_valid_extension(extension): return any(re.match(pattern, str(extension)) for pattern in patterns) +def xform_replace_missing_prefix(audits): + """Replaces missing ALN prefixes with the corresponding value in CFDA""" + change_records = [] + is_empty_prefix_found = False + for audit in audits: + prefix = string_to_string(audit.CFDA_PREFIX) + if not prefix: + is_empty_prefix_found = True + prefix = string_to_string(audit.CFDA).split(".")[0] + + track_transformations( + "CFDA_PREFIX", + audit.CFDA_PREFIX, + "federal_agency_prefix", + prefix, + ["xform_replace_missing_prefix"], + change_records, + ) + + audit.CFDA_PREFIX = prefix + + # See Transformation Method Change Recording at the top of this file. + if change_records and is_empty_prefix_found: + InspectionRecord.append_federal_awards_changes(change_records) + + def xform_replace_invalid_extension(audit): """Replaces invalid ALN extensions with the default value settings.GSA_MIGRATION.""" prefix = string_to_string(audit.CFDA_PREFIX) @@ -574,7 +600,7 @@ def xform_populate_default_passthrough_names_ids(audits): range(len(audits)), audits, passthrough_names, passthrough_ids ): direct = string_to_string(audit.DIRECT) - if direct == "N" and name == "": + if direct in {"N", settings.GSA_MIGRATION} and name == "": passthrough_names[index] = settings.GSA_MIGRATION if direct == "N" and id == "": passthrough_ids[index] = settings.GSA_MIGRATION @@ -802,6 +828,40 @@ def track_invalid_federal_program_total(audits, cfda_key_values): ) +def xform_replace_required_values_with_gsa_migration_when_empty(audits): + """Replace empty fields with GSA_MIGRATION.""" + fields_to_check = [ + ("LOANS", "is_loan"), + ("DIRECT", "is_direct"), + ] + + for in_db, in_dissem in fields_to_check: + _replace_empty_field(audits, in_db, in_dissem) + + +def _replace_empty_field(audits, name_in_db, name_in_dissem): + """Replace empty fields with GSA_MIGRATION.""" + change_records = [] + has_empty_field = False + for audit in audits: + current_value = getattr(audit, name_in_db) + if not string_to_string(current_value): + has_empty_field = True + setattr(audit, name_in_db, settings.GSA_MIGRATION) + + track_transformations( + name_in_db, + current_value, + name_in_dissem, + settings.GSA_MIGRATION, + ["xform_replace_required_values_with_gsa_migration_when_empty"], + change_records, + ) + + if change_records and has_empty_field: + InspectionRecord.append_federal_awards_changes(change_records) + + def generate_federal_awards(audit_header, outfile): """ Generates a federal awards workbook for all awards associated with a given audit header. @@ -833,7 +893,8 @@ def generate_federal_awards(audit_header, outfile): xform_program_name(audits) xform_is_passthrough_award(audits) xform_missing_major_program(audits) - + xform_replace_required_values_with_gsa_migration_when_empty(audits) + xform_replace_missing_prefix(audits) map_simple_columns(wb, mappings, audits) set_range(wb, "cluster_name", cluster_names) diff --git a/backend/schemas/output/sections/FederalAwards.schema.json b/backend/schemas/output/sections/FederalAwards.schema.json index dbf726aed9..bb49ef4d44 100644 --- a/backend/schemas/output/sections/FederalAwards.schema.json +++ b/backend/schemas/output/sections/FederalAwards.schema.json @@ -326,7 +326,8 @@ "is_guaranteed": { "enum": [ "Y", - "N" + "N", + "GSA_MIGRATION" ], "type": "string" }, diff --git a/backend/schemas/source/sections/FederalAwards.schema.jsonnet b/backend/schemas/source/sections/FederalAwards.schema.jsonnet index 783ea8bd68..cf09523344 100644 --- a/backend/schemas/source/sections/FederalAwards.schema.jsonnet +++ b/backend/schemas/source/sections/FederalAwards.schema.jsonnet @@ -311,7 +311,7 @@ local Parts = { additionalProperties: false, description: 'A loan or loan guarantee and balance', properties: { - is_guaranteed: Base.Enum.YorN, + is_guaranteed: Base.Enum.YorNorGsaMigration, loan_balance_at_audit_period_end: { anyOf: [ Types.integer, From f438cee198cbd57a4a211715a8c73bc54c3eb94b Mon Sep 17 00:00:00 2001 From: "Hassan D. M. Sambo" Date: Tue, 11 Jun 2024 15:00:42 -0400 Subject: [PATCH 2/4] 3951 address historical report with missing auditee contact title (#3956) * #3951 Added logic to handle empty auditee contact title * #3951 Added test case --- .../sac_general_lib/general_information.py | 16 +++++++++++ .../test_general_information_xforms.py | 27 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/backend/census_historical_migration/sac_general_lib/general_information.py b/backend/census_historical_migration/sac_general_lib/general_information.py index 32ad3c20ba..3addfaaf8a 100644 --- a/backend/census_historical_migration/sac_general_lib/general_information.py +++ b/backend/census_historical_migration/sac_general_lib/general_information.py @@ -416,6 +416,21 @@ def xform_replace_empty_auditee_contact_name(general_information): return general_information +def xform_replace_empty_auditee_contact_title(general_information): + """Replaces empty auditee contact title with GSA Migration keyword""" + # Transformation recorded. + if not general_information.get("auditee_contact_title"): + general_information["auditee_contact_title"] = settings.GSA_MIGRATION + track_transformations( + "AUDITEETITLE", + "", + "auditee_contact_title", + general_information["auditee_contact_title"], + "xform_replace_empty_auditee_contact_title", + ) + return general_information + + def xform_replace_empty_or_invalid_auditee_uei_with_gsa_migration(audit_header): """Replaces empty or invalid auditee UEI with GSA Migration keyword""" # Transformation recorded. @@ -563,6 +578,7 @@ def general_information(audit_header): xform_replace_empty_or_invalid_auditee_ein_with_gsa_migration, xform_replace_empty_zips, xform_replace_empty_auditee_contact_name, + xform_replace_empty_auditee_contact_title, ] for transform in transformations: diff --git a/backend/census_historical_migration/test_general_information_xforms.py b/backend/census_historical_migration/test_general_information_xforms.py index 6c2a0a69d1..a1084dd1ab 100644 --- a/backend/census_historical_migration/test_general_information_xforms.py +++ b/backend/census_historical_migration/test_general_information_xforms.py @@ -15,6 +15,7 @@ xform_country_v2, xform_entity_type, xform_replace_empty_auditee_contact_name, + xform_replace_empty_auditee_contact_title, xform_replace_empty_auditor_email, xform_replace_empty_auditee_email, xform_replace_empty_or_invalid_auditee_uei_with_gsa_migration, @@ -319,6 +320,32 @@ def test_missing_auditee_contact_name(self): ) +class TestXformReplaceEmptyAuditeeContactTitle(SimpleTestCase): + def test_empty_auditee_contact_title(self): + """Test that an empty auditee_contact_title is replaced with 'GSA_MIGRATION'""" + input_data = {"auditee_contact_title": ""} + expected_output = {"auditee_contact_title": settings.GSA_MIGRATION} + self.assertEqual( + xform_replace_empty_auditee_contact_title(input_data), expected_output + ) + + def test_non_empty_auditee_contact_title(self): + """Test that a non-empty auditee_contact_title remains unchanged""" + input_data = {"auditee_contact_title": "test"} + expected_output = {"auditee_contact_title": "test"} + self.assertEqual( + xform_replace_empty_auditee_contact_title(input_data), expected_output + ) + + def test_missing_auditee_contact_title(self): + """Test that a missing auditee_contact_title key is added and set to 'GSA_MIGRATION'""" + input_data = {} + expected_output = {"auditee_contact_title": settings.GSA_MIGRATION} + self.assertEqual( + xform_replace_empty_auditee_contact_title(input_data), expected_output + ) + + class TestXformReplaceEmptyOrInvalidUEIs(SimpleTestCase): class MockAuditHeader: def __init__(self, UEI): From 24a05e03662670d514eeba8923ec8d0e1480ea02 Mon Sep 17 00:00:00 2001 From: "Hassan D. M. Sambo" Date: Tue, 11 Jun 2024 15:01:51 -0400 Subject: [PATCH 3/4] 3945 address historical report with invalid secondary auditor phone contact (#3947) * #3945 Updated code to pad a nine digit phone contact * Linting * #3945 Added test case * Update backend/census_historical_migration/workbooklib/secondary_auditors.py Co-authored-by: Phil Dominguez <142051477+phildominguez-gsa@users.noreply.github.com> --------- Co-authored-by: Phil Dominguez <142051477+phildominguez-gsa@users.noreply.github.com> --- .../test_secondary_auditors_xforms.py | 41 +++++++++++++++++++ .../workbooklib/secondary_auditors.py | 25 +++++++++++ 2 files changed, 66 insertions(+) diff --git a/backend/census_historical_migration/test_secondary_auditors_xforms.py b/backend/census_historical_migration/test_secondary_auditors_xforms.py index 6994ca81fa..dbaeafa632 100644 --- a/backend/census_historical_migration/test_secondary_auditors_xforms.py +++ b/backend/census_historical_migration/test_secondary_auditors_xforms.py @@ -1,10 +1,13 @@ from django.conf import settings from django.test import SimpleTestCase +from census_historical_migration.change_record import InspectionRecord + from .workbooklib.secondary_auditors import ( xform_address_state, xform_address_zipcode, xform_cpafirmname, + xform_pad_contact_phone_with_nine, ) @@ -101,3 +104,41 @@ def test_blank_cpafirm(self): xform_cpafirmname(secondary_auditors) self.assertEqual(secondary_auditors[0].CPAFIRMNAME, settings.GSA_MIGRATION) self.assertEqual(secondary_auditors[1].CPAFIRMNAME, cpas[1].CPAFIRMNAME) + + +class TestXformPadContactPhoneWithNine(SimpleTestCase): + + class MockSecondaryAuditorHeader: + + def __init__( + self, + CPAPHONE, + ): + self.CPAPHONE = CPAPHONE + + def setUp(self): + self.secondary_auditors = [ + self.MockSecondaryAuditorHeader(CPAPHONE="12345"), + self.MockSecondaryAuditorHeader(CPAPHONE="999999999"), + self.MockSecondaryAuditorHeader(CPAPHONE="1234567890"), + self.MockSecondaryAuditorHeader(CPAPHONE="98765432"), + ] + + def test_pad_contact_phone(self): + xform_pad_contact_phone_with_nine(self.secondary_auditors) + + self.assertEqual(self.secondary_auditors[0].CPAPHONE, "12345") # No change + self.assertEqual( + self.secondary_auditors[1].CPAPHONE, "9999999999" + ) # Pad applied + self.assertEqual(self.secondary_auditors[2].CPAPHONE, "1234567890") # No change + self.assertEqual(self.secondary_auditors[3].CPAPHONE, "98765432") # No change + + def test_change_records(self): + secondary_auditors = [self.MockSecondaryAuditorHeader(CPAPHONE="999999999")] + change_records_before = len(InspectionRecord.change["secondary_auditor"]) + + xform_pad_contact_phone_with_nine(secondary_auditors) + + change_records_after = len(InspectionRecord.change["secondary_auditor"]) + self.assertEqual(change_records_after, change_records_before + 1) diff --git a/backend/census_historical_migration/workbooklib/secondary_auditors.py b/backend/census_historical_migration/workbooklib/secondary_auditors.py index c47ff12ca1..a6b10a81dc 100644 --- a/backend/census_historical_migration/workbooklib/secondary_auditors.py +++ b/backend/census_historical_migration/workbooklib/secondary_auditors.py @@ -155,6 +155,30 @@ def xform_cpafirmname(secondary_auditors): InspectionRecord.append_secondary_auditor_changes(change_records) +def xform_pad_contact_phone_with_nine(secondary_auditors): + """Pad contact phone with 9s if less than 10 digits""" + change_records = [] + is_pad_applied = False + for secondary_auditor in secondary_auditors: + contact_phone = string_to_string(secondary_auditor.CPAPHONE) + if contact_phone == "999999999": + contact_phone = "9999999999" + is_pad_applied = True + track_transformations( + "CPAPHONE", + secondary_auditor.CPAPHONE, + "contact_phone", + contact_phone, + ["xform_contact_phone"], + change_records, + ) + secondary_auditor.CPAPHONE = contact_phone + + # See Transformation Method Change Recording comment at the top of this file + if change_records and is_pad_applied: + InspectionRecord.append_secondary_auditor_changes(change_records) + + def generate_secondary_auditors(audit_header, outfile): """ Generates secondary auditor workbook for a given audit header. @@ -174,6 +198,7 @@ def generate_secondary_auditors(audit_header, outfile): xform_address_state(secondary_auditors) xform_address_zipcode(secondary_auditors) xform_cpafirmname(secondary_auditors) + xform_pad_contact_phone_with_nine(secondary_auditors) map_simple_columns(wb, mappings, secondary_auditors) wb.save(outfile) From f2aa937fb2ec4202775948126d2088cf8e853211 Mon Sep 17 00:00:00 2001 From: Sudha Kumar <135276194+gsa-suk@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:22:21 -0700 Subject: [PATCH 4/4] Sk/3955 blank finding refnums (#3964) * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Handling blank finding reference number * Update backend/audit/intakelib/checks/check_finding_reference_pattern.py Co-authored-by: Hassan D. M. Sambo --------- Co-authored-by: Hassan D. M. Sambo --- .../checks/check_finding_reference_pattern.py | 9 ++++++--- .../checks/check_gsa_migration_keyword.py | 1 + backend/audit/intakelib/checks/runners.py | 2 +- .../test_findings_xforms.py | 8 ++++++++ .../workbooklib/corrective_action_plan.py | 2 ++ .../workbooklib/findings.py | 1 + .../workbooklib/findings_text.py | 2 ++ .../sections/AuditFindingsText.schema.json | 16 ++++++++++++---- .../sections/CorrectiveActionPlan.schema.json | 16 ++++++++++++---- .../FederalAwardsAuditFindings.schema.json | 16 ++++++++++++---- .../sections/AuditFindingsText.schema.jsonnet | 9 ++++++++- .../sections/CorrectiveActionPlan.schema.jsonnet | 9 ++++++++- .../FederalAwardsAuditFindings.schema.jsonnet | 9 ++++++++- 13 files changed, 81 insertions(+), 19 deletions(-) diff --git a/backend/audit/intakelib/checks/check_finding_reference_pattern.py b/backend/audit/intakelib/checks/check_finding_reference_pattern.py index e33c2350a3..092117b3c8 100644 --- a/backend/audit/intakelib/checks/check_finding_reference_pattern.py +++ b/backend/audit/intakelib/checks/check_finding_reference_pattern.py @@ -9,6 +9,7 @@ build_cell_error_tuple, appears_empty, ) +from django.conf import settings logger = logging.getLogger(__name__) @@ -21,12 +22,14 @@ # digits are a year >= 1900. # TESTED BY # has_bad_references.xlsx -def finding_reference_pattern(ir): +def finding_reference_pattern(ir, is_gsa_migration=False): references = get_range_by_name(ir, "reference_number") errors = [] for index, reference in enumerate(references["values"]): - if not appears_empty(reference) and ( - not re.match(FINDING_REFERENCE_REGEX, str(reference)) + if ( + not appears_empty(reference) + and (reference == settings.GSA_MIGRATION and not is_gsa_migration) + and (not re.match(FINDING_REFERENCE_REGEX, str(reference))) ): errors.append( build_cell_error_tuple( diff --git a/backend/audit/intakelib/checks/check_gsa_migration_keyword.py b/backend/audit/intakelib/checks/check_gsa_migration_keyword.py index 2a4a5e4140..70502c1c4c 100644 --- a/backend/audit/intakelib/checks/check_gsa_migration_keyword.py +++ b/backend/audit/intakelib/checks/check_gsa_migration_keyword.py @@ -44,6 +44,7 @@ def check_for_gsa_migration_keyword(ir): "material_weakness", "significant_deficiency", "repeat_prior_reference", + "reference_number", "is_guaranteed", ] diff --git a/backend/audit/intakelib/checks/runners.py b/backend/audit/intakelib/checks/runners.py index 03f5cdd626..2bf9fd2906 100644 --- a/backend/audit/intakelib/checks/runners.py +++ b/backend/audit/intakelib/checks/runners.py @@ -153,7 +153,7 @@ "federal_program_total_is_correct": federal_program_total_is_correct, } -require_gsa_migration_flag = [findings_grid_validation] +require_gsa_migration_flag = [findings_grid_validation, finding_reference_pattern] def run_all_checks( diff --git a/backend/census_historical_migration/test_findings_xforms.py b/backend/census_historical_migration/test_findings_xforms.py index 62b300e041..1c03050c91 100644 --- a/backend/census_historical_migration/test_findings_xforms.py +++ b/backend/census_historical_migration/test_findings_xforms.py @@ -266,6 +266,7 @@ def __init__( SIGNIFICANTDEFICIENCY, OTHERFINDINGS, QCOSTS, + FINDINGREFNUMS, ): self.MODIFIEDOPINION = MODIFIEDOPINION self.OTHERNONCOMPLIANCE = OTHERNONCOMPLIANCE @@ -273,6 +274,7 @@ def __init__( self.SIGNIFICANTDEFICIENCY = SIGNIFICANTDEFICIENCY self.OTHERFINDINGS = OTHERFINDINGS self.QCOSTS = QCOSTS + self.FINDINGREFNUMS = FINDINGREFNUMS def test_replace_empty_fields(self): findings = [ @@ -283,6 +285,7 @@ def test_replace_empty_fields(self): SIGNIFICANTDEFICIENCY="", OTHERFINDINGS="Present", QCOSTS="", + FINDINGREFNUMS="", ), self.Finding( MODIFIEDOPINION="Present", @@ -291,6 +294,7 @@ def test_replace_empty_fields(self): SIGNIFICANTDEFICIENCY="", OTHERFINDINGS="Present", QCOSTS="", + FINDINGREFNUMS="Present", ), self.Finding( MODIFIEDOPINION="", @@ -299,6 +303,7 @@ def test_replace_empty_fields(self): SIGNIFICANTDEFICIENCY="", OTHERFINDINGS="", QCOSTS="Present", + FINDINGREFNUMS="", ), ] @@ -310,6 +315,7 @@ def test_replace_empty_fields(self): self.assertEqual(findings[0].SIGNIFICANTDEFICIENCY, settings.GSA_MIGRATION) self.assertEqual(findings[0].OTHERFINDINGS, "Present") self.assertEqual(findings[0].QCOSTS, settings.GSA_MIGRATION) + self.assertEqual(findings[0].FINDINGREFNUMS, settings.GSA_MIGRATION) self.assertEqual(findings[1].MODIFIEDOPINION, "Present") self.assertEqual(findings[1].OTHERNONCOMPLIANCE, "Present") @@ -317,6 +323,7 @@ def test_replace_empty_fields(self): self.assertEqual(findings[1].SIGNIFICANTDEFICIENCY, settings.GSA_MIGRATION) self.assertEqual(findings[1].OTHERFINDINGS, "Present") self.assertEqual(findings[1].QCOSTS, settings.GSA_MIGRATION) + self.assertEqual(findings[1].FINDINGREFNUMS, "Present") self.assertEqual(findings[2].MODIFIEDOPINION, settings.GSA_MIGRATION) self.assertEqual(findings[2].OTHERNONCOMPLIANCE, "Present") @@ -324,6 +331,7 @@ def test_replace_empty_fields(self): self.assertEqual(findings[2].SIGNIFICANTDEFICIENCY, settings.GSA_MIGRATION) self.assertEqual(findings[2].OTHERFINDINGS, settings.GSA_MIGRATION) self.assertEqual(findings[2].QCOSTS, "Present") + self.assertEqual(findings[2].FINDINGREFNUMS, settings.GSA_MIGRATION) class TestXformMissingRepeatPriorReference(SimpleTestCase): diff --git a/backend/census_historical_migration/workbooklib/corrective_action_plan.py b/backend/census_historical_migration/workbooklib/corrective_action_plan.py index 6ef09cef1e..ebb74c8db0 100644 --- a/backend/census_historical_migration/workbooklib/corrective_action_plan.py +++ b/backend/census_historical_migration/workbooklib/corrective_action_plan.py @@ -61,6 +61,8 @@ def xform_add_placeholder_for_missing_references(findings, captexts): missing_references = expected_references - found_references if missing_references: for ref in missing_references: + if not ref: + ref = settings.GSA_MIGRATION captexts.append( CapText( SEQ_NUMBER="0", diff --git a/backend/census_historical_migration/workbooklib/findings.py b/backend/census_historical_migration/workbooklib/findings.py index 903bcc3b36..eb231cd8d1 100644 --- a/backend/census_historical_migration/workbooklib/findings.py +++ b/backend/census_historical_migration/workbooklib/findings.py @@ -268,6 +268,7 @@ def xform_replace_required_fields_with_gsa_migration_when_empty(findings): ("SIGNIFICANTDEFICIENCY", "is_significant_deficiency"), ("OTHERFINDINGS", "is_other_findings"), ("QCOSTS", "is_questioned_costs"), + ("FINDINGREFNUMS", "reference_number"), ] for in_db, in_dissem in fields_to_check: diff --git a/backend/census_historical_migration/workbooklib/findings_text.py b/backend/census_historical_migration/workbooklib/findings_text.py index 2960f1e589..7c1fe33086 100644 --- a/backend/census_historical_migration/workbooklib/findings_text.py +++ b/backend/census_historical_migration/workbooklib/findings_text.py @@ -63,6 +63,8 @@ def xform_add_placeholder_for_missing_references(findings, findings_texts): if missing_references: for ref in missing_references: + if not ref: + ref = settings.GSA_MIGRATION findings_texts.append( FindingsText( SEQ_NUMBER="0", diff --git a/backend/schemas/output/sections/AuditFindingsText.schema.json b/backend/schemas/output/sections/AuditFindingsText.schema.json index 30c2d7ccae..d4dc995fdb 100644 --- a/backend/schemas/output/sections/AuditFindingsText.schema.json +++ b/backend/schemas/output/sections/AuditFindingsText.schema.json @@ -45,10 +45,18 @@ "type": "string" }, "reference_number": { - "description": "Reference Number", - "pattern": "^[1-2][0-9]{3}-[0-9]{3}$", - "title": "ReferenceNumber", - "type": "string" + "oneOf": [ + { + "description": "Reference Number", + "pattern": "^[1-2][0-9]{3}-[0-9]{3}$", + "title": "ReferenceNumber", + "type": "string" + }, + { + "const": "GSA_MIGRATION", + "type": "string" + } + ] }, "text_of_finding": { "type": "string" diff --git a/backend/schemas/output/sections/CorrectiveActionPlan.schema.json b/backend/schemas/output/sections/CorrectiveActionPlan.schema.json index 9378bf2055..9f60738cab 100644 --- a/backend/schemas/output/sections/CorrectiveActionPlan.schema.json +++ b/backend/schemas/output/sections/CorrectiveActionPlan.schema.json @@ -48,10 +48,18 @@ "type": "string" }, "reference_number": { - "description": "Reference Number", - "pattern": "^[1-2][0-9]{3}-[0-9]{3}$", - "title": "ReferenceNumber", - "type": "string" + "oneOf": [ + { + "description": "Reference Number", + "pattern": "^[1-2][0-9]{3}-[0-9]{3}$", + "title": "ReferenceNumber", + "type": "string" + }, + { + "const": "GSA_MIGRATION", + "type": "string" + } + ] } }, "required": [ diff --git a/backend/schemas/output/sections/FederalAwardsAuditFindings.schema.json b/backend/schemas/output/sections/FederalAwardsAuditFindings.schema.json index 5cbc8fe35f..5bd77b9af1 100644 --- a/backend/schemas/output/sections/FederalAwardsAuditFindings.schema.json +++ b/backend/schemas/output/sections/FederalAwardsAuditFindings.schema.json @@ -341,10 +341,18 @@ "type": "string" }, "reference_number": { - "description": "Reference Number", - "pattern": "^[1-2][0-9]{3}-[0-9]{3}$", - "title": "ReferenceNumber", - "type": "string" + "oneOf": [ + { + "description": "Reference Number", + "pattern": "^[1-2][0-9]{3}-[0-9]{3}$", + "title": "ReferenceNumber", + "type": "string" + }, + { + "const": "GSA_MIGRATION", + "type": "string" + } + ] }, "repeat_prior_reference": { "enum": [ diff --git a/backend/schemas/source/sections/AuditFindingsText.schema.jsonnet b/backend/schemas/source/sections/AuditFindingsText.schema.jsonnet index 45aa62d66e..35e0da571b 100644 --- a/backend/schemas/source/sections/AuditFindingsText.schema.jsonnet +++ b/backend/schemas/source/sections/AuditFindingsText.schema.jsonnet @@ -23,7 +23,14 @@ local Meta = Types.object { local FindingsTextEntry = { additionalProperties: false, properties: { - reference_number: Base.Compound.ReferenceNumber, + reference_number: { + oneOf: [ + Base.Compound.ReferenceNumber, + Types.string { + const: Base.Const.GSA_MIGRATION, + }, + ], + }, text_of_finding: Types.string, contains_chart_or_table: Base.Enum.YorNorGsaMigration, }, diff --git a/backend/schemas/source/sections/CorrectiveActionPlan.schema.jsonnet b/backend/schemas/source/sections/CorrectiveActionPlan.schema.jsonnet index 41303f3357..ecc3888460 100644 --- a/backend/schemas/source/sections/CorrectiveActionPlan.schema.jsonnet +++ b/backend/schemas/source/sections/CorrectiveActionPlan.schema.jsonnet @@ -23,7 +23,14 @@ local Meta = Types.object { local CorrectiveActionPlanEntry = { additionalProperties: false, properties: { - reference_number: Base.Compound.ReferenceNumber, + reference_number: { + oneOf: [ + Base.Compound.ReferenceNumber, + Types.string { + const: Base.Const.GSA_MIGRATION, + }, + ], + }, planned_action: Types.string, contains_chart_or_table: Base.Enum.YorNorGsaMigration, }, diff --git a/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet b/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet index f6c733b7f7..436e9739d2 100644 --- a/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet +++ b/backend/schemas/source/sections/FederalAwardsAuditFindings.schema.jsonnet @@ -42,7 +42,14 @@ local Parts = { Findings: Types.object { additionalProperties: false, properties: { - reference_number: Base.Compound.ReferenceNumber, + reference_number: { + oneOf: [ + Base.Compound.ReferenceNumber, + Types.string { + const: Base.Const.GSA_MIGRATION, + }, + ], + }, is_valid: Base.Enum.YorNorGsaMigration, repeat_prior_reference: Base.Enum.YorNorGsaMigration, prior_references: Types.string,