Skip to content

Commit

Permalink
3705 address historical federal awards with extraneous passthrough na…
Browse files Browse the repository at this point in the history
…mes (#3811)

* #3705 Added logic to handle cases where award is direct but record contains passthrough name and id

* #3705 Added  python validation for the schema validation

* Code improvement
  • Loading branch information
sambodeme authored May 9, 2024
1 parent e4c5b8e commit 4c2fa9a
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@


# `GSA_MIGRATION` is a default value assigned to any required fields
# that are missing, ensuring validation during the data migration process.
# that are missing or invalid, ensuring validation during the data migration process.
# See Ticket https://github.com/GSA-TTS/FAC/issues/2912.
# This function is to ensure the `GSA_MIGRATION` keyword is only used
# in the context of data migration.
Expand All @@ -26,6 +26,7 @@ def check_for_gsa_migration_keyword(ir):
"state_cluster_name",
"other_cluster_name",
"cluster_name",
"is_direct",
"loan_balance_at_audit_period_end",
"passthrough_name",
"passthrough_identifying_number",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import logging

from django.conf import settings
from audit.intakelib.intermediate_representation import get_range_by_name
from audit.intakelib.common import get_message, build_cell_error_tuple

Expand Down Expand Up @@ -52,5 +54,14 @@ def passthrough_name_when_no_direct(ir):
get_message("check_passthrough_name_when_yes_direct"),
)
)
elif (isd == settings.GSA_MIGRATION) and (not pname):
errors.append(
build_cell_error_tuple(
ir,
is_direct,
ndx,
get_message("check_passthrough_name_when_invalid_direct"),
)
)

return errors
1 change: 1 addition & 0 deletions backend/audit/intakelib/common/error_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"check_other_cluster_names_no_other_cluster_needed": "Other cluster must be blank unless you are selecting OTHER CLUSTER",
"check_direct_award_is_not_blank": "Direct award cannot be blank; it must be <b>Y</b> or <b>N</b>",
"check_passthrough_name_when_no_direct": "If direct award is <b>N</b>, then you must provide a passthrough name",
"check_passthrough_name_when_invalid_direct": "If direct award is <b>GSA_MIGRATION</b>, then passthrough name must not be blank",
"check_loan_guarantee_empty_when_n": "When loan guarantee is <b>N</b>, outstanding balance must be empty",
"check_loan_guarantee_present_when_y": "When loan guarantee is <b>Y</b>, there must be a loan balance",
"check_is_right_workbook": "This is not the {} workbook",
Expand Down
23 changes: 23 additions & 0 deletions backend/census_historical_migration/test_federal_awards_xforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
xform_constructs_cluster_names,
xform_populate_default_passthrough_amount,
xform_populate_default_passthrough_names_ids,
xform_replace_invalid_direct_award_flag,
xform_replace_invalid_extension,
xform_program_name,
xform_is_passthrough_award,
Expand Down Expand Up @@ -667,3 +668,25 @@ def test_cluster_name_other_cluster(self):
result = xform_cluster_names(audits)
for audit in result:
self.assertEqual(audit.CLUSTERNAME, settings.OTHER_CLUSTER)


class TestXformReplaceInvalidDirectAwardFlag(SimpleTestCase):
class MockAudit:
def __init__(self, direct_flag):
self.DIRECT = direct_flag

def test_replace_invalid_direct_award_flag(self):
audits = [self.MockAudit("Y"), self.MockAudit("N"), self.MockAudit("Y")]
passthrough_names = [
"some name",
"some other name",
"",
]

results = xform_replace_invalid_direct_award_flag(audits, passthrough_names)
# Expect first audit DIRECT flag to be replaced with default
self.assertEqual(results[0], settings.GSA_MIGRATION)
# Expect second audit DIRECT flag to remain unchanged
self.assertEqual(results[1], "N")
# Expect third audit DIRECT flag to remain unchanged
self.assertEqual(results[2], "Y")
43 changes: 39 additions & 4 deletions backend/census_historical_migration/workbooklib/federal_awards.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,7 @@
SheetFieldMap(
"loan_balance_at_audit_period_end", "LOANBALANCE", "loan_balance", None, str
),
SheetFieldMap("is_direct", "DIRECT", WorkbookFieldInDissem, None, uppercase_y_or_n),
SheetFieldMap(
"is_passed", "PASSTHROUGHAWARD", "is_passthrough_award", None, uppercase_y_or_n
),
SheetFieldMap("is_passed", "PASSTHROUGHAWARD", "is_passthrough_award", None, str),
SheetFieldMap(
"subrecipient_amount",
"PASSTHROUGHAMOUNT",
Expand Down Expand Up @@ -483,6 +480,41 @@ def xform_populate_default_passthrough_names_ids(audits):
return (passthrough_names, passthrough_ids)


def xform_replace_invalid_direct_award_flag(audits, passthrough_names):
"""Replaces invalid DIRECT award flags with the default value settings.GSA_MIGRATION."""
is_directs = []
change_records = []
is_invalid_direct_flag_found = False
for audit, name in zip(audits, passthrough_names):
is_direct = string_to_string(audit.DIRECT)
if is_direct == "Y" and name:
is_invalid_direct_flag_found = True
track_transformations(
"DIRECT",
audit.DIRECT,
"is_direct",
settings.GSA_MIGRATION,
["xform_replace_invalid_direct_award_flag"],
change_records,
)
is_directs.append(settings.GSA_MIGRATION)
else:
track_transformations(
"DIRECT",
is_direct,
"is_direct",
is_direct,
["xform_replace_invalid_direct_award_flag"],
change_records,
)
is_directs.append(is_direct)

if change_records and is_invalid_direct_flag_found:
InspectionRecord.append_federal_awards_changes(change_records)

return is_directs


def xform_populate_default_loan_balance(audits):
"""
Automatically fills in default values for empty loan balances.
Expand Down Expand Up @@ -650,6 +682,9 @@ def generate_federal_awards(audit_header, outfile):
set_range(wb, "passthrough_name", passthrough_names)
set_range(wb, "passthrough_identifying_number", passthrough_ids)

is_directs = xform_replace_invalid_direct_award_flag(audits, passthrough_names)
set_range(wb, "is_direct", is_directs)

# The award numbers!
set_range(
wb,
Expand Down
32 changes: 27 additions & 5 deletions backend/schemas/output/sections/FederalAwards.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,20 @@
]
}
},
{
"if": {
"properties": {
"is_direct": {
"const": "GSA_MIGRATION"
}
}
},
"then": {
"required": [
"entities"
]
}
},
{
"if": {
"properties": {
Expand Down Expand Up @@ -251,11 +265,19 @@
"type": "array"
},
"is_direct": {
"enum": [
"Y",
"N"
],
"type": "string"
"oneOf": [
{
"enum": [
"Y",
"N"
],
"type": "string"
},
{
"const": "GSA_MIGRATION",
"type": "string"
}
]
}
},
"type": "object"
Expand Down
21 changes: 20 additions & 1 deletion backend/schemas/source/sections/FederalAwards.schema.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,14 @@ local Parts = {
additionalProperties: false,
description: 'If direct_award is N, the form must include a list of the pass-through entity by name and identifying number',
properties: {
is_direct: Base.Enum.YorN,
is_direct: {
oneOf: [
Base.Enum.YorN,
Types.string {
const: Base.Const.GSA_MIGRATION,
},
],
},
entities: Types.array {
items: Validations.PassThroughEntity,
},
Expand All @@ -272,6 +279,18 @@ local Parts = {
required: ['entities'],
},
},
{
'if': {
properties: {
is_direct: {
const: Base.Const.GSA_MIGRATION,
},
},
},
'then': {
required: ['entities'],
},
},
{
'if': {
properties: {
Expand Down

0 comments on commit 4c2fa9a

Please sign in to comment.