diff --git a/backend/audit/intakelib/checks/check_finding_reference_year.py b/backend/audit/intakelib/checks/check_finding_reference_year.py new file mode 100644 index 0000000000..5a4dbd9a39 --- /dev/null +++ b/backend/audit/intakelib/checks/check_finding_reference_year.py @@ -0,0 +1,47 @@ +import logging +from django.core.exceptions import ValidationError +from audit.intakelib.intermediate_representation import ( + get_range_by_name, +) +from audit.intakelib.common import ( + get_message, + build_cell_error_tuple, +) + +from audit.context import get_sac_from_context +from audit.intakelib.common.util import get_range_start_row + +logger = logging.getLogger(__name__) + + +# DESCRIPTION +# Finding references should be in 20##-### format where the first four +# digits match the audit_year. + + +def finding_reference_year(ir, is_gsa_migration=False): + references = get_range_by_name(ir, "reference_number") + range_start = int(get_range_start_row(references)) + errors = [] + if is_gsa_migration: + return errors + sac = get_sac_from_context() + audit_date = sac.general_information["auditee_fiscal_period_end"] + audit_year = int(audit_date.split("-")[0]) + for index, reference in enumerate(references["values"]): + year = int(reference.split("-")[0]) + if audit_year != year: + errors.append( + build_cell_error_tuple( + ir, + references, + index, + get_message("check_invalid_finding_reference_year").format( + reference, index + range_start, audit_year + ), + ) + ) + + if len(errors) > 0: + logger.info("Raising a validation error.") + raise ValidationError(errors) diff --git a/backend/audit/intakelib/checks/runners.py b/backend/audit/intakelib/checks/runners.py index 5e0e502f2d..fb5a4457c4 100644 --- a/backend/audit/intakelib/checks/runners.py +++ b/backend/audit/intakelib/checks/runners.py @@ -56,6 +56,7 @@ from .check_findings_grid_validation import findings_grid_validation from .check_finding_prior_references_pattern import prior_references_pattern from .check_finding_reference_pattern import finding_reference_pattern +from .check_finding_reference_year import finding_reference_year from .check_aln_prefix_pattern import aln_agency_prefix logger = logging.getLogger(__name__) @@ -111,6 +112,7 @@ award_references_pattern, prior_references_pattern, finding_reference_pattern, + finding_reference_year, no_repeat_findings, findings_grid_validation, # See ticket #4385 for more information on why this check is disabled diff --git a/backend/audit/intakelib/common/error_messages.py b/backend/audit/intakelib/common/error_messages.py index 88ea14df37..170cf560f6 100644 --- a/backend/audit/intakelib/common/error_messages.py +++ b/backend/audit/intakelib/common/error_messages.py @@ -69,6 +69,7 @@ "check_aln_three_digit_extension_invalid": "The three digit extension should follow one of these formats: ###, RD#, or U##, where # represents a number", "check_prior_references_invalid": "Prior references must be N/A or a comma-separated list of values in the format 20##-###, for example, 2019-001, 2019-002", "check_finding_reference_invalid": "Finding references must be in the format 20##-### where the first four digits are a year after 2010, for example, 2019-001, 2019-002", + "check_invalid_finding_reference_year": "The reference year in the finding reference {} declared in row {} does not match the audit year {}", "check_award_references_invalid": "Combining award references of 4 and 5-digit lengths is not allowed. If needed, zero-pad this number to make it 5 digits", "check_aln_prefix_invalid": "The federal agency prefix should be a two-digit value, for example, 10", "check_additional_award_identification_present": "Missing additional award identification", diff --git a/backend/audit/views/views.py b/backend/audit/views/views.py index c5a87acf72..1448055a7c 100644 --- a/backend/audit/views/views.py +++ b/backend/audit/views/views.py @@ -44,6 +44,7 @@ ) from audit.utils import FORM_SECTION_HANDLERS +from audit.context import set_sac_to_context from dissemination.remove_workbook_artifacts import remove_workbook_artifacts from dissemination.file_downloads import get_download_url, get_filename from dissemination.models import General @@ -233,14 +234,14 @@ def post(self, request, *_args, **kwargs): and "auditee_uei" in sac.general_information ): auditee_uei = sac.general_information["auditee_uei"] + with set_sac_to_context(sac): + audit_data = self._extract_and_validate_data( + form_section, excel_file, auditee_uei + ) - audit_data = self._extract_and_validate_data( - form_section, excel_file, auditee_uei - ) - - self._save_audit_data(sac, form_section, audit_data) + self._save_audit_data(sac, form_section, audit_data) - return redirect("/") + return redirect("/") except SingleAuditChecklist.DoesNotExist as err: logger.warning("no SingleAuditChecklist found with report ID %s", report_id)