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 e0c62087ef..f09e14b492 100644 --- a/backend/census_historical_migration/sac_general_lib/general_information.py +++ b/backend/census_historical_migration/sac_general_lib/general_information.py @@ -147,8 +147,8 @@ def xform_update_multiple_eins_flag(audit_header): This updates does not propagate to the database, it only updates the object. """ if not string_to_string(audit_header.MULTIPLEEINS): - queryset = get_eins(audit_header.DBKEY, audit_header.AUDITYEAR) - audit_header.MULTIPLEEINS = "Y" if queryset.exists() else "N" + eins = get_eins(audit_header.DBKEY, audit_header.AUDITYEAR) + audit_header.MULTIPLEEINS = "Y" if eins else "N" def xform_update_multiple_ueis_flag(audit_header): @@ -156,8 +156,8 @@ def xform_update_multiple_ueis_flag(audit_header): This updates does not propagate to the database, it only updates the object. """ if not string_to_string(audit_header.MULTIPLEUEIS): - queryset = get_ueis(audit_header.DBKEY, audit_header.AUDITYEAR) - audit_header.MULTIPLEUEIS = "Y" if queryset.exists() else "N" + ueis = get_ueis(audit_header.DBKEY, audit_header.AUDITYEAR) + audit_header.MULTIPLEUEIS = "Y" if ueis else "N" def _period_covered(s): @@ -284,6 +284,21 @@ def xform_audit_type(general_information): return general_information +def xform_replace_empty_auditor_email(general_information): + """Replaces empty auditor email with GSA Migration keyword""" + # Transformation recorded. + if not general_information.get("auditor_email"): + general_information["auditor_email"] = settings.GSA_MIGRATION + track_transformations( + "CPAEMAIL", + "", + "auditor_email", + general_information["auditor_email"], + "xform_replace_empty_auditor_email", + ) + return general_information + + def track_transformations( census_column, census_value, gsa_field, gsa_value, transformation_functions ): @@ -311,6 +326,7 @@ def general_information(audit_header): xform_country, xform_audit_period_covered, xform_audit_type, + xform_replace_empty_auditor_email, ] 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 79003cf8cb..c1fb1901b7 100644 --- a/backend/census_historical_migration/test_general_information_xforms.py +++ b/backend/census_historical_migration/test_general_information_xforms.py @@ -1,4 +1,5 @@ from datetime import datetime, timedelta +from django.conf import settings from django.test import SimpleTestCase from .sac_general_lib.general_information import ( @@ -10,6 +11,7 @@ xform_auditee_fiscal_period_start, xform_country, xform_entity_type, + xform_replace_empty_auditor_email, ) from .exception_utils import ( DataMigrationError, @@ -211,3 +213,23 @@ def test_missing_audit_type(self): general_information = {} with self.assertRaises(DataMigrationError): xform_audit_type(general_information) + + +class TestXformReplaceEmptyAuditorEmail(SimpleTestCase): + def test_empty_auditor_email(self): + """Test that an empty auditor_email is replaced with 'GSA_MIGRATION'""" + input_data = {"auditor_email": ""} + expected_output = {"auditor_email": settings.GSA_MIGRATION} + self.assertEqual(xform_replace_empty_auditor_email(input_data), expected_output) + + def test_non_empty_auditor_email(self): + """Test that a non-empty auditor_email remains unchanged""" + input_data = {"auditor_email": "test@example.com"} + expected_output = {"auditor_email": "test@example.com"} + self.assertEqual(xform_replace_empty_auditor_email(input_data), expected_output) + + def test_missing_auditor_email(self): + """Test that a missing auditor_email key is added and set to 'GSA_MIGRATION'""" + input_data = {} + expected_output = {"auditor_email": settings.GSA_MIGRATION} + self.assertEqual(xform_replace_empty_auditor_email(input_data), expected_output) diff --git a/backend/census_historical_migration/workbooklib/notes_to_sefa.py b/backend/census_historical_migration/workbooklib/notes_to_sefa.py index 625858a814..43ec5b837d 100644 --- a/backend/census_historical_migration/workbooklib/notes_to_sefa.py +++ b/backend/census_historical_migration/workbooklib/notes_to_sefa.py @@ -68,11 +68,23 @@ def xform_is_minimis_rate_used(rate_content): r"not\s+us(e|ed)", r"not\s+elec(t|ted)", r"has\s+not\s+charged.*not\s+applicable", + r"has\s+elected\s+not", r"did\s+not\s+charge\s+indirect\s+costs", + r"did\s+not\s+make\s+an\s+election", + r"not\s+eligible\s+to\s+use", + r"made\s+no\s+inderect\s+cost\s+rate\s+election", + r"rather\s+than\s+the\s+10%", ] # Patterns that indicate the de minimis rate WAS used - used_patterns = [r"used", r"elected\s+to\s+use", r"uses.*allowed"] + used_patterns = [ + r"used", + r"elected\s+to\s+use", + r"uses.*allowed", + r"has\s+adopted", + r"elected\s+to", + r"is\s+subject\s+to\s+the\s+10-percent", + ] # Check for each pattern in the respective lists for pattern in not_used_patterns: diff --git a/backend/schemas/output/sections/GeneralInformation.schema.json b/backend/schemas/output/sections/GeneralInformation.schema.json index 96e8812781..638ee0d886 100644 --- a/backend/schemas/output/sections/GeneralInformation.schema.json +++ b/backend/schemas/output/sections/GeneralInformation.schema.json @@ -442,17 +442,21 @@ "type": "boolean" }, "auditor_email": { - "maxLength": 100, "oneOf": [ { - "format": "email" + "format": "email", + "maxLength": 100, + "type": "string" + }, + { + "const": "GSA_MIGRATION", + "type": "string" }, { "const": "", "type": "string" } - ], - "type": "string" + ] }, "auditor_firm_name": { "maxLength": 100, diff --git a/backend/schemas/output/sections/GeneralInformationComplete.schema.json b/backend/schemas/output/sections/GeneralInformationComplete.schema.json index 476fb4afa1..b068e6e571 100644 --- a/backend/schemas/output/sections/GeneralInformationComplete.schema.json +++ b/backend/schemas/output/sections/GeneralInformationComplete.schema.json @@ -308,10 +308,18 @@ "type": "boolean" }, "auditor_email": { - "format": "email", - "maxLength": 100, - "minLength": 1, - "type": "string" + "oneOf": [ + { + "format": "email", + "maxLength": 100, + "minLength": 1, + "type": "string" + }, + { + "const": "GSA_MIGRATION", + "type": "string" + } + ] }, "auditor_firm_name": { "maxLength": 100, diff --git a/backend/schemas/output/sections/GeneralInformationRequired.schema.json b/backend/schemas/output/sections/GeneralInformationRequired.schema.json index ca001806a3..ffe67fe813 100644 --- a/backend/schemas/output/sections/GeneralInformationRequired.schema.json +++ b/backend/schemas/output/sections/GeneralInformationRequired.schema.json @@ -442,17 +442,21 @@ "type": "boolean" }, "auditor_email": { - "maxLength": 100, "oneOf": [ { - "format": "email" + "format": "email", + "maxLength": 100, + "type": "string" + }, + { + "const": "GSA_MIGRATION", + "type": "string" }, { "const": "", "type": "string" } - ], - "type": "string" + ] }, "auditor_firm_name": { "maxLength": 100, diff --git a/backend/schemas/source/sections/GeneralInformation.schema.jsonnet b/backend/schemas/source/sections/GeneralInformation.schema.jsonnet index e783a483de..2e3a657540 100644 --- a/backend/schemas/source/sections/GeneralInformation.schema.jsonnet +++ b/backend/schemas/source/sections/GeneralInformation.schema.jsonnet @@ -146,16 +146,18 @@ Typechecks fields, but allows for empty data as well. Contains conditional Check Base.Compound.EmptyString, ], }, - auditor_email: Types.string { + auditor_email: { oneOf: [ - { + Types.string { format: 'email', + maxLength: 100, + }, + Types.string { + const: Base.Const.GSA_MIGRATION, }, Base.Compound.EmptyString, ], - maxLength: 100, }, - // Others is_usa_based: Types.boolean, met_spending_threshold: Types.boolean, diff --git a/backend/schemas/source/sections/GeneralInformationComplete.schema.jsonnet b/backend/schemas/source/sections/GeneralInformationComplete.schema.jsonnet index 407eaac153..eb976e4375 100644 --- a/backend/schemas/source/sections/GeneralInformationComplete.schema.jsonnet +++ b/backend/schemas/source/sections/GeneralInformationComplete.schema.jsonnet @@ -101,12 +101,18 @@ Requires most fields, has consitional checks for conditional fields. minLength: 1, }, auditor_phone: Base.Compound.UnitedStatesPhone, - auditor_email: Types.string { - format: 'email', - maxLength: 100, - minLength: 1, + auditor_email: { + oneOf: [ + Types.string { + format: 'email', + maxLength: 100, + minLength: 1, + }, + Types.string { + const: Base.Const.GSA_MIGRATION, + }, + ], }, - // Others is_usa_based: Types.boolean, met_spending_threshold: Types.boolean,