def test_happy_path(client, agency_data): resp = client.get(URL.format(code="001", filter="")) assert resp.status_code == status.HTTP_200_OK assert resp.data["fiscal_year"] == current_fiscal_year() assert resp.data["toptier_code"] == "001" assert resp.data["abbreviation"] == "ABBR" assert resp.data["name"] == "NAME" assert resp.data["mission"] == "TO BOLDLY GO" assert resp.data["about_agency_data"] == "ABOUT" assert resp.data["website"] == "HTTP" assert resp.data["congressional_justification_url"] == "BECAUSE" assert resp.data["icon_filename"] == "HAI.jpg" assert resp.data["subtier_agency_count"] == 1 assert resp.data["messages"] == [] resp = client.get(URL.format(code="001", filter=f"?fiscal_year={current_fiscal_year()}")) assert resp.status_code == status.HTTP_200_OK assert resp.data["fiscal_year"] == current_fiscal_year() assert resp.data["toptier_code"] == "001" assert resp.data["subtier_agency_count"] == 1 resp = client.get(URL.format(code="001", filter=f"?fiscal_year={current_fiscal_year() - 1}")) assert resp.status_code == status.HTTP_200_OK assert resp.data["fiscal_year"] == current_fiscal_year() - 1 assert resp.data["toptier_code"] == "001" assert resp.data["subtier_agency_count"] == 1 resp = client.get(URL.format(code="002", filter="")) assert resp.status_code == status.HTTP_200_OK assert resp.data["fiscal_year"] == current_fiscal_year() assert resp.data["toptier_code"] == "002" assert resp.data["subtier_agency_count"] == 0
def test_budget_function_list_search(client, agency_account_data): query_params = f"?fiscal_year={current_fiscal_year()}&filter=NAME 6" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "next": None, "page": 1, "previous": None, "total": 1, "limit": 10, }, "results": [ { "gross_outlay_amount": 100000.0, "name": "NAME 6", "obligated_amount": 100.0, "children": [{"gross_outlay_amount": 100000.0, "name": "NAME 6A", "obligated_amount": 100.0}], } ], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result query_params = f"?fiscal_year={current_fiscal_year()}&filter=AME 5" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "next": None, "page": 1, "previous": None, "total": 1, "limit": 10, }, "results": [ { "gross_outlay_amount": 1000000.0, "name": "NAME 5", "obligated_amount": 10.0, "children": [{"gross_outlay_amount": 1000000.0, "name": "NAME 5A", "obligated_amount": 10.0}], } ], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result
def test_object_class_list_search(client, agency_account_data): query_params = f"?fiscal_year={current_fiscal_year()}&filter=supplies" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "limit": 10, "next": None, "page": 1, "previous": None, "total": 1, }, "results": [{ "gross_outlay_amount": 100000.0, "name": "supplies", "obligated_amount": 100.0 }], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result query_params = f"?fiscal_year={current_fiscal_year()}&filter=uipm" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "limit": 10, "next": None, "page": 1, "previous": None, "total": 1, }, "results": [{ "gross_outlay_amount": 10000000.0, "name": "equipment", "obligated_amount": 1.0 }], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result
def agency_data(): ta1 = mommy.make( "references.ToptierAgency", toptier_code="001", abbreviation="ABBR", name="NAME", mission="TO BOLDLY GO", about_agency_data="ABOUT", website="HTTP", justification="BECAUSE", icon_filename="HAI.jpg", ) ta2 = mommy.make("references.ToptierAgency", toptier_code="002") sa1 = mommy.make("references.SubtierAgency", subtier_code="ST1") sa2 = mommy.make("references.SubtierAgency", subtier_code="ST2") a1 = mommy.make("references.Agency", id=1, toptier_flag=True, toptier_agency=ta1, subtier_agency=sa1) mommy.make("references.Agency", id=2, toptier_flag=True, toptier_agency=ta2, subtier_agency=sa2) tas1 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1) tas2 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta2) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas1) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas2) mommy.make("awards.TransactionNormalized", awarding_agency=a1, fiscal_year=current_fiscal_year()) dabs = mommy.make("submissions.DABSSubmissionWindowSchedule", submission_reveal_date="2020-10-09") mommy.make("submissions.SubmissionAttributes", toptier_code=ta1.toptier_code, submission_window_id=dabs.id) mommy.make("submissions.SubmissionAttributes", toptier_code=ta2.toptier_code, submission_window_id=dabs.id)
def fiscal_year(self): fiscal_year = str( self.request.query_params.get("fiscal_year", current_fiscal_year())) if not fullmatch("[0-9]{4}", fiscal_year): raise UnprocessableEntityException( "Unrecognized fiscal_year format. Should be YYYY.") min_fiscal_year = fy(settings.API_SEARCH_MIN_DATE) fiscal_year = int(fiscal_year) if fiscal_year < min_fiscal_year: raise UnprocessableEntityException( f"fiscal_year is currently limited to an earliest year of {min_fiscal_year}." ) if fiscal_year > current_fiscal_year(): raise UnprocessableEntityException( f"fiscal_year may not exceed current fiscal year of {current_fiscal_year()}." ) return fiscal_year
def agency_data(): ta1 = mommy.make( "references.ToptierAgency", toptier_code="001", abbreviation="ABBR", name="NAME", mission="TO BOLDLY GO", about_agency_data="ABOUT", website="HTTP", justification="BECAUSE", icon_filename="HAI.jpg", ) ta2 = mommy.make("references.ToptierAgency", toptier_code="002") sa1 = mommy.make("references.SubtierAgency", subtier_code="ST1") sa2 = mommy.make("references.SubtierAgency", subtier_code="ST2") a1 = mommy.make("references.Agency", id=1, toptier_flag=True, toptier_agency=ta1, subtier_agency=sa1) mommy.make("references.Agency", id=2, toptier_flag=True, toptier_agency=ta2, subtier_agency=sa2) tas1 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1) tas2 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta2) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas1) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas2) mommy.make("awards.TransactionNormalized", awarding_agency=a1, fiscal_year=current_fiscal_year()) dabs = mommy.make("submissions.DABSSubmissionWindowSchedule", submission_reveal_date="2020-10-09") sub1 = mommy.make( "submissions.SubmissionAttributes", toptier_code=ta1.toptier_code, submission_window_id=dabs.id, reporting_fiscal_year=current_fiscal_year(), ) mommy.make("submissions.SubmissionAttributes", toptier_code=ta2.toptier_code, submission_window_id=dabs.id) defc = mommy.make( "references.DisasterEmergencyFundCode", code="L", group_name="covid_19", public_law="LAW", title="title" ) mommy.make( "financial_activities.FinancialAccountsByProgramActivityObjectClass", submission=sub1, treasury_account=tas1, disaster_emergency_fund=defc, )
def get_agency_budgetary_resources(self): aab = (AppropriationAccountBalances.objects.filter( treasury_account_identifier__funding_toptier_agency=self. toptier_agency, submission__submission_window__submission_reveal_date__lte=now(), submission__is_final_balances_for_fy=True, ).values("submission__reporting_fiscal_year").annotate( agency_budgetary_resources=Sum( "total_budgetary_resources_amount_cpe"), agency_total_obligated=Sum( "obligations_incurred_total_by_tas_cpe"), )) fbr = self.get_total_federal_budgetary_resources() resources = {} for z in fbr: resources.update( {z["fiscal_year"]: z["total_budgetary_resources"]}) results = [{ "fiscal_year": x["submission__reporting_fiscal_year"], "agency_budgetary_resources": x["agency_budgetary_resources"], "agency_total_obligated": x["agency_total_obligated"], "total_budgetary_resources": resources.get(x["submission__reporting_fiscal_year"]), } for x in aab] years = [x["fiscal_year"] for x in results] for year in range(2017, current_fiscal_year() + 1): if year not in years: results.append({ "fiscal_year": year, "agency_budgetary_resources": None, "agency_total_obligated": None, "total_budgetary_resources": resources.get(year), }) return sorted(results, key=lambda x: x["fiscal_year"], reverse=True)
def agency_data(): ta1 = mommy.make( "references.ToptierAgency", toptier_code="001", abbreviation="ABBR", name="NAME", mission="TO BOLDLY GO", about_agency_data="ABOUT", website="HTTP", justification="BECAUSE", icon_filename="HAI.jpg", ) ta2 = mommy.make("references.ToptierAgency", toptier_code="002") sa1 = mommy.make("references.SubtierAgency", subtier_code="ST1") sa2 = mommy.make("references.SubtierAgency", subtier_code="ST2") a1 = mommy.make("references.Agency", toptier_agency=ta1, subtier_agency=sa1) mommy.make("references.Agency", toptier_agency=ta2, subtier_agency=sa2) tas1 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1) tas2 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta2) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas1) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas2) mommy.make("awards.TransactionNormalized", awarding_agency=a1, fiscal_year=current_fiscal_year())
def test_budgetary_resources(client, data_fixture): resp = client.get(URL.format(code="001", filter="")) expected_results = [ { "fiscal_year": FY, "agency_budgetary_resources": Decimal("29992.00"), "total_budgetary_resources": Decimal(f"{FY}.00"), "agency_total_obligated": Decimal("26661.00"), }, { "fiscal_year": PRIOR_FY, "agency_budgetary_resources": Decimal("15.00"), "total_budgetary_resources": Decimal(f"{PRIOR_FY}.00"), "agency_total_obligated": Decimal("5.00"), }, ] for year in range(2017, current_fiscal_year() + 1): if year != FY and year != PRIOR_FY: expected_results.append({ "fiscal_year": year, "agency_budgetary_resources": None, "total_budgetary_resources": Decimal(f"{year}.00"), "agency_total_obligated": None, }) expected_results = sorted(expected_results, key=lambda x: x["fiscal_year"], reverse=True) assert resp.data == { "toptier_code": "001", "agency_data_by_year": expected_results, "messages": [], }
def test_federal_account_list_future(client, agency_account_data): query_params = "?fiscal_year=" + str(current_fiscal_year() + 1) resp = client.get(url.format(code="007", query_params=query_params)) assert resp.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
def agency_account_data(): ta1 = mommy.make("references.ToptierAgency", toptier_code="007") ta2 = mommy.make("references.ToptierAgency", toptier_code="008") ta3 = mommy.make("references.ToptierAgency", toptier_code="009") ta4 = mommy.make("references.ToptierAgency", toptier_code="010") sub1 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=current_fiscal_year()) sub2 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=2017) sub3 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=2018) sub4 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=2019) sub5 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=2016) fa1 = mommy.make("accounts.FederalAccount", federal_account_code="001-0000", account_title="FA 1") fa2 = mommy.make("accounts.FederalAccount", federal_account_code="002-0000", account_title="FA 2") fa3 = mommy.make("accounts.FederalAccount", federal_account_code="003-0000", account_title="FA 3") fa4 = mommy.make("accounts.FederalAccount", federal_account_code="004-0000", account_title="FA 4") tas1 = mommy.make( "accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1, budget_function_code=100, budget_function_title="NAME 1", budget_subfunction_code=1100, budget_subfunction_title="NAME 1A", federal_account=fa1, account_title="TA 1", tas_rendering_label="001-X-0000-000", ) tas2 = mommy.make( "accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta2, budget_function_code=200, budget_function_title="NAME 2", budget_subfunction_code=2100, budget_subfunction_title="NAME 2A", federal_account=fa2, account_title="TA 2", tas_rendering_label="002-X-0000-000", ) tas3 = mommy.make( "accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta3, budget_function_code=300, budget_function_title="NAME 3", budget_subfunction_code=3100, budget_subfunction_title="NAME 3A", federal_account=fa3, account_title="TA 3", tas_rendering_label="003-X-0000-000", ) tas4 = mommy.make( "accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta4, budget_function_code=400, budget_function_title="NAME 4", budget_subfunction_code=4100, budget_subfunction_title="NAME 4A", federal_account=fa4, account_title="TA 4", tas_rendering_label="001-X-0000-000", ) tas5 = mommy.make( "accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1, budget_function_code=200, budget_function_title="NAME 5", budget_subfunction_code=2100, budget_subfunction_title="NAME 5A", federal_account=fa2, account_title="TA 5", tas_rendering_label="002-2008/2009-0000-000", ) tas6 = mommy.make( "accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1, budget_function_code=300, budget_function_title="NAME 6", budget_subfunction_code=3100, budget_subfunction_title="NAME 6A", federal_account=fa3, account_title="TA 6", tas_rendering_label="003-2017/2018-0000-000", ) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas1) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas2) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas3) mommy.make("accounts.AppropriationAccountBalances", treasury_account_identifier=tas4) pa1 = mommy.make("references.RefProgramActivity", program_activity_code="000", program_activity_name="NAME 1") pa2 = mommy.make("references.RefProgramActivity", program_activity_code="1000", program_activity_name="NAME 2") pa3 = mommy.make("references.RefProgramActivity", program_activity_code="4567", program_activity_name="NAME 3") pa4 = mommy.make("references.RefProgramActivity", program_activity_code="111", program_activity_name="NAME 4") pa5 = mommy.make("references.RefProgramActivity", program_activity_code="1234", program_activity_name="NAME 5") oc = "references.ObjectClass" oc1 = mommy.make( oc, major_object_class=10, major_object_class_name="Other", object_class=100, object_class_name="equipment" ) oc2 = mommy.make( oc, major_object_class=10, major_object_class_name="Other", object_class=110, object_class_name="hvac" ) oc3 = mommy.make( oc, major_object_class=10, major_object_class_name="Other", object_class=120, object_class_name="supplies" ) oc4 = mommy.make( oc, major_object_class=10, major_object_class_name="Other", object_class=130, object_class_name="interest" ) oc5 = mommy.make( oc, major_object_class=10, major_object_class_name="Other", object_class=140, object_class_name="interest" ) fabpaoc = "financial_activities.FinancialAccountsByProgramActivityObjectClass" mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas1, submission=sub1, program_activity=pa1, object_class=oc1, obligations_incurred_by_program_object_class_cpe=1, gross_outlay_amount_by_program_object_class_cpe=10000000, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas1, submission=sub1, program_activity=pa2, object_class=oc2, obligations_incurred_by_program_object_class_cpe=10, gross_outlay_amount_by_program_object_class_cpe=1000000, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas1, submission=sub1, program_activity=pa3, object_class=oc3, obligations_incurred_by_program_object_class_cpe=100, gross_outlay_amount_by_program_object_class_cpe=100000, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas2, submission=sub2, program_activity=pa4, object_class=oc4, obligations_incurred_by_program_object_class_cpe=1000, gross_outlay_amount_by_program_object_class_cpe=10000, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas2, submission=sub3, program_activity=pa4, object_class=oc3, obligations_incurred_by_program_object_class_cpe=10000, gross_outlay_amount_by_program_object_class_cpe=1000, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas3, submission=sub3, program_activity=pa4, object_class=oc3, obligations_incurred_by_program_object_class_cpe=100000, gross_outlay_amount_by_program_object_class_cpe=100, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas3, submission=sub4, program_activity=pa4, object_class=oc4, obligations_incurred_by_program_object_class_cpe=1000000, gross_outlay_amount_by_program_object_class_cpe=10, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas3, submission=sub4, program_activity=pa4, object_class=oc4, obligations_incurred_by_program_object_class_cpe=10000000, gross_outlay_amount_by_program_object_class_cpe=1, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas4, submission=sub5, program_activity=pa5, object_class=oc5, obligations_incurred_by_program_object_class_cpe=0, gross_outlay_amount_by_program_object_class_cpe=0, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas5, submission=sub1, obligations_incurred_by_program_object_class_cpe=10, gross_outlay_amount_by_program_object_class_cpe=1000000, ) mommy.make( fabpaoc, final_of_fy=True, treasury_account=tas6, submission=sub1, obligations_incurred_by_program_object_class_cpe=100, gross_outlay_amount_by_program_object_class_cpe=100000, )
def test_program_activity_list_pagination(client, agency_account_data): query_params = f"?fiscal_year={current_fiscal_year()}&limit=2&page=1" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": True, "hasPrevious": False, "limit": 2, "next": 2, "page": 1, "previous": None, "total": 3, }, "results": [ { "gross_outlay_amount": 100000.0, "name": "NAME 3", "obligated_amount": 100.0 }, { "gross_outlay_amount": 1000000.0, "name": "NAME 2", "obligated_amount": 10.0 }, ], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result query_params = f"?fiscal_year={current_fiscal_year()}&limit=2&page=2" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": True, "limit": 2, "next": None, "page": 2, "previous": 1, "total": 3, }, "results": [{ "gross_outlay_amount": 10000000.0, "name": "NAME 1", "obligated_amount": 1.0 }], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result
def test_program_activity_list_success(client, agency_account_data): resp = client.get(url.format(code="007", query_params="")) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "limit": 10, "next": None, "page": 1, "previous": None, "total": 3, }, "results": [ { "gross_outlay_amount": 100000.0, "name": "NAME 3", "obligated_amount": 100.0 }, { "gross_outlay_amount": 1000000.0, "name": "NAME 2", "obligated_amount": 10.0 }, { "gross_outlay_amount": 10000000.0, "name": "NAME 1", "obligated_amount": 1.0 }, ], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result query_params = "?fiscal_year=2017" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": 2017, "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "limit": 10, "next": None, "page": 1, "previous": None, "total": 0, }, "results": [], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result query_params = "?fiscal_year=2016" resp = client.get(url.format(code="010", query_params=query_params)) expected_result = { "fiscal_year": 2016, "toptier_code": "010", "messages": [ "Account data powering this endpoint were first collected in " "FY2017 Q2 under the DATA Act; as such, there are no data " "available for prior fiscal years." ], "page_metadata": { "hasNext": False, "hasPrevious": False, "limit": 10, "next": None, "page": 1, "previous": None, "total": 0, }, "results": [], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result
import pytest from decimal import Decimal from model_mommy import mommy from rest_framework import status from usaspending_api.common.helpers.fiscal_year_helpers import current_fiscal_year URL = "/api/v2/agency/{code}/budgetary_resources/{filter}" FY = current_fiscal_year() - 2 PRIOR_FY = FY - 1 @pytest.fixture def data_fixture(): ta1 = mommy.make("references.ToptierAgency", toptier_code="001") ta2 = mommy.make("references.ToptierAgency", toptier_code="002") tas1 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1) tas2 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta2) sa1_3 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=FY, reporting_fiscal_period=3) sa1_6 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=FY, reporting_fiscal_period=6) sa1_9 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=FY, reporting_fiscal_period=9) sa1_12 = mommy.make("submissions.SubmissionAttributes", reporting_fiscal_year=FY,
def data_fixture(): dabs = mommy.make( "submissions.DABSSubmissionWindowSchedule", submission_fiscal_year=1995, submission_fiscal_month=2, submission_reveal_date="2020-10-09", ) ta1 = mommy.make("references.ToptierAgency", toptier_code="001") ta2 = mommy.make("references.ToptierAgency", toptier_code="002") mommy.make("references.Agency", toptier_flag=True, toptier_agency=ta1) mommy.make("references.Agency", toptier_flag=True, toptier_agency=ta2) tas1 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta1) tas2 = mommy.make("accounts.TreasuryAppropriationAccount", funding_toptier_agency=ta2) sa1_3 = mommy.make( "submissions.SubmissionAttributes", reporting_fiscal_year=FY, reporting_fiscal_period=3, submission_window=dabs, toptier_code=ta1.toptier_code, is_final_balances_for_fy=True, ) sa1_6 = mommy.make( "submissions.SubmissionAttributes", reporting_fiscal_year=FY, reporting_fiscal_period=6, submission_window=dabs, toptier_code=ta1.toptier_code, is_final_balances_for_fy=True, ) sa1_9 = mommy.make( "submissions.SubmissionAttributes", reporting_fiscal_year=FY, reporting_fiscal_period=9, submission_window=dabs, toptier_code=ta1.toptier_code, is_final_balances_for_fy=True, ) sa1_12 = mommy.make( "submissions.SubmissionAttributes", reporting_fiscal_year=FY, reporting_fiscal_period=12, submission_window=dabs, toptier_code=ta1.toptier_code, is_final_balances_for_fy=True, ) sa2_12 = mommy.make( "submissions.SubmissionAttributes", reporting_fiscal_year=PRIOR_FY, reporting_fiscal_period=12, submission_window_id=dabs.id, toptier_code=ta2.toptier_code, is_final_balances_for_fy=True, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=9993, obligations_incurred_total_by_tas_cpe=8883, treasury_account_identifier=tas1, submission=sa1_3, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=9996, obligations_incurred_total_by_tas_cpe=8886, treasury_account_identifier=tas1, submission=sa1_6, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=9999, obligations_incurred_total_by_tas_cpe=8889, treasury_account_identifier=tas1, submission=sa1_9, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=1, obligations_incurred_total_by_tas_cpe=1, treasury_account_identifier=tas1, submission=sa1_12, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=3, obligations_incurred_total_by_tas_cpe=2, treasury_account_identifier=tas1, submission=sa1_12, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=15, obligations_incurred_total_by_tas_cpe=5, treasury_account_identifier=tas1, submission=sa2_12, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=31, obligations_incurred_total_by_tas_cpe=6, treasury_account_identifier=tas2, submission=sa1_12, ) mommy.make( "accounts.AppropriationAccountBalances", total_budgetary_resources_amount_cpe=63, obligations_incurred_total_by_tas_cpe=7, treasury_account_identifier=tas2, submission=sa2_12, ) for fy in range(2017, current_fiscal_year() + 1): mommy.make("references.GTASSF133Balances", fiscal_year=fy, fiscal_period=12, total_budgetary_resources_cpe=fy) mommy.make( "submissions.DABSSubmissionWindowSchedule", submission_fiscal_year=fy, submission_fiscal_month=12, submission_reveal_date="2020-10-09", is_quarter=True, )
import pytest from django.conf import settings from model_mommy import mommy from rest_framework import status from usaspending_api.common.helpers.fiscal_year_helpers import ( current_fiscal_year, calculate_last_completed_fiscal_quarter, get_final_period_of_quarter, ) url = "/api/v2/reporting/agencies/overview/" CURRENT_FISCAL_YEAR = current_fiscal_year() CURRENT_LAST_QUARTER = calculate_last_completed_fiscal_quarter( CURRENT_FISCAL_YEAR) or 1 CURRENT_LAST_PERIOD = get_final_period_of_quarter(CURRENT_LAST_QUARTER) or 3 assurance_statement_1 = ( f"{settings.FILES_SERVER_BASE_URL}/agency_submissions/Raw%20DATA%20Act%20Files/" "2019/P06/123%20-%20Test%20Agency%20(ABC)/2019-P06-123_Test%20Agency%20(ABC)-Assurance_Statement.txt" ) assurance_statement_2 = ( f"{settings.FILES_SERVER_BASE_URL}/agency_submissions/Raw%20DATA%20Act%20Files/" f"{CURRENT_FISCAL_YEAR}/P{CURRENT_LAST_PERIOD:02}/987%20-%20Test%20Agency%202%20(XYZ)/" f"{CURRENT_FISCAL_YEAR}-P{CURRENT_LAST_PERIOD:02}-987_Test%20Agency%202%20(XYZ)-Assurance_Statement.txt" ) assurance_statement_3 = ( f"{settings.FILES_SERVER_BASE_URL}/agency_submissions/Raw%20DATA%20Act%20Files/" f"{CURRENT_FISCAL_YEAR}/Q{CURRENT_LAST_QUARTER}/001%20-%20Test%20Agency%203%20(AAA)/"
def setup_test_data(db): """ Insert data into DB for testing """ dabs = mommy.make("submissions.DABSSubmissionWindowSchedule", submission_reveal_date="2020-10-09") sub = mommy.make( "submissions.SubmissionAttributes", submission_id=1, toptier_code="123", quarter_format_flag=False, reporting_fiscal_year=2019, reporting_fiscal_period=6, published_date="2019-07-03", submission_window_id=dabs.id, ) sub2 = mommy.make( "submissions.SubmissionAttributes", submission_id=2, toptier_code="987", quarter_format_flag=False, reporting_fiscal_year=CURRENT_FISCAL_YEAR, reporting_fiscal_period=CURRENT_LAST_PERIOD, published_date=f"{CURRENT_FISCAL_YEAR}-{CURRENT_LAST_PERIOD+1:02}-07", submission_window_id=dabs.id, ) sub3 = mommy.make( "submissions.SubmissionAttributes", submission_id=3, toptier_code="001", quarter_format_flag=True, reporting_fiscal_year=CURRENT_FISCAL_YEAR, reporting_fiscal_period=CURRENT_LAST_PERIOD, published_date=f"{CURRENT_FISCAL_YEAR}-{CURRENT_LAST_PERIOD+1:02}-07", submission_window_id=dabs.id, ) mommy.make("references.Agency", id=1, toptier_agency_id=1, toptier_flag=True) mommy.make("references.Agency", id=2, toptier_agency_id=2, toptier_flag=True) mommy.make("references.Agency", id=3, toptier_agency_id=3, toptier_flag=True) agencies = [ mommy.make("references.ToptierAgency", toptier_agency_id=1, toptier_code="123", abbreviation="ABC", name="Test Agency"), mommy.make( "references.ToptierAgency", toptier_agency_id=2, toptier_code="987", abbreviation="XYZ", name="Test Agency 2", ), mommy.make( "references.ToptierAgency", toptier_agency_id=3, toptier_code="001", abbreviation="AAA", name="Test Agency 3", ), ] treas_accounts = [ mommy.make( "accounts.TreasuryAppropriationAccount", treasury_account_identifier=1, awarding_toptier_agency_id=agencies[0].toptier_agency_id, tas_rendering_label="tas-1-overview", ), mommy.make( "accounts.TreasuryAppropriationAccount", treasury_account_identifier=2, awarding_toptier_agency_id=agencies[2].toptier_agency_id, tas_rendering_label="tas-2-overview", ), mommy.make( "accounts.TreasuryAppropriationAccount", treasury_account_identifier=3, awarding_toptier_agency_id=agencies[1].toptier_agency_id, tas_rendering_label="tas-3-overview", ), ] approps = [ { "sub_id": sub.submission_id, "treasury_account": treas_accounts[0], "total_resources": 50 }, { "sub_id": sub3.submission_id, "treasury_account": treas_accounts[1], "total_resources": 12 }, { "sub_id": sub3.submission_id, "treasury_account": treas_accounts[1], "total_resources": 29 }, { "sub_id": sub2.submission_id, "treasury_account": treas_accounts[2], "total_resources": 15.5 }, ] for approp in approps: mommy.make( "accounts.AppropriationAccountBalances", submission_id=approp["sub_id"], treasury_account_identifier=approp["treasury_account"], total_budgetary_resources_amount_cpe=approp["total_resources"], ) reporting_tases = [ { "year": sub.reporting_fiscal_year, "period": sub.reporting_fiscal_period, "label": treas_accounts[0].tas_rendering_label, "toptier_code": agencies[0].toptier_code, "diff": 29.5, }, { "year": sub2.reporting_fiscal_year, "period": sub2.reporting_fiscal_period, "label": treas_accounts[1].tas_rendering_label, "toptier_code": agencies[2].toptier_code, "diff": -1.3, }, { "year": sub2.reporting_fiscal_year, "period": sub2.reporting_fiscal_period, "label": treas_accounts[2].tas_rendering_label, "toptier_code": agencies[1].toptier_code, "diff": 20.5, }, ] for reporting_tas in reporting_tases: mommy.make( "reporting.ReportingAgencyTas", fiscal_year=reporting_tas["year"], fiscal_period=reporting_tas["period"], tas_rendering_label=reporting_tas["label"], toptier_code=reporting_tas["toptier_code"], diff_approp_ocpa_obligated_amounts=reporting_tas["diff"], appropriation_obligated_amount=100, ) mommy.make( "reporting.ReportingAgencyOverview", reporting_agency_overview_id=1, toptier_code="123", fiscal_year=2019, fiscal_period=6, total_dollars_obligated_gtas=1788370.03, total_budgetary_resources=22478810.97, total_diff_approp_ocpa_obligated_amounts=84931.95, unlinked_procurement_c_awards=1, unlinked_assistance_c_awards=2, unlinked_procurement_d_awards=3, unlinked_assistance_d_awards=4, ) mommy.make( "reporting.ReportingAgencyOverview", reporting_agency_overview_id=2, toptier_code="987", fiscal_year=CURRENT_FISCAL_YEAR, fiscal_period=CURRENT_LAST_PERIOD, total_dollars_obligated_gtas=18.6, total_budgetary_resources=100, total_diff_approp_ocpa_obligated_amounts=0, unlinked_procurement_c_awards=10, unlinked_assistance_c_awards=20, unlinked_procurement_d_awards=30, unlinked_assistance_d_awards=40, ) mommy.make( "reporting.ReportingAgencyOverview", reporting_agency_overview_id=3, toptier_code="001", fiscal_year=CURRENT_FISCAL_YEAR, fiscal_period=CURRENT_LAST_PERIOD, total_dollars_obligated_gtas=20.0, total_budgetary_resources=10.0, total_diff_approp_ocpa_obligated_amounts=10.0, unlinked_procurement_c_awards=100, unlinked_assistance_c_awards=200, unlinked_procurement_d_awards=300, unlinked_assistance_d_awards=400, ) mommy.make( "reporting.ReportingAgencyMissingTas", toptier_code="123", fiscal_year=2019, fiscal_period=6, tas_rendering_label="TAS 1", obligated_amount=10.0, ) mommy.make( "reporting.ReportingAgencyMissingTas", toptier_code="123", fiscal_year=2019, fiscal_period=6, tas_rendering_label="TAS 2", obligated_amount=1.0, ) mommy.make( "reporting.ReportingAgencyMissingTas", toptier_code="987", fiscal_year=CURRENT_FISCAL_YEAR, fiscal_period=CURRENT_LAST_PERIOD, tas_rendering_label="TAS 2", obligated_amount=12.0, ) mommy.make( "reporting.ReportingAgencyMissingTas", toptier_code="987", fiscal_year=current_fiscal_year(), fiscal_period=get_final_period_of_quarter( calculate_last_completed_fiscal_quarter(current_fiscal_year())) or 3, tas_rendering_label="TAS 3", obligated_amount=0, )
def test_federal_account_list_success(client, agency_account_data): resp = client.get(url.format(code="007", query_params="")) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "next": None, "page": 1, "previous": None, "total": 3, "limit": 10, }, "results": [ { "gross_outlay_amount": 11100000.0, "name": "FA 1", "code": "001-0000", "obligated_amount": 111.0, "children": [{ "gross_outlay_amount": 11100000.0, "name": "TA 1", "code": "001-X-0000-000", "obligated_amount": 111.0, }], }, { "gross_outlay_amount": 100000.0, "name": "FA 3", "code": "003-0000", "obligated_amount": 100.0, "children": [{ "gross_outlay_amount": 100000.0, "name": "TA 6", "code": "003-2017/2018-0000-000", "obligated_amount": 100.0, }], }, { "gross_outlay_amount": 1000000.0, "name": "FA 2", "code": "002-0000", "obligated_amount": 10.0, "children": [{ "gross_outlay_amount": 1000000.0, "name": "TA 5", "code": "002-2008/2009-0000-000", "obligated_amount": 10.0, }], }, ], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result query_params = "?fiscal_year=2017" resp = client.get(url.format(code="008", query_params=query_params)) expected_result = { "fiscal_year": 2017, "toptier_code": "008", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": False, "next": None, "page": 1, "previous": None, "total": 1, "limit": 10, }, "results": [{ "gross_outlay_amount": 10000.0, "name": "FA 2", "code": "002-0000", "obligated_amount": 1000.0, "children": [{ "gross_outlay_amount": 10000.0, "name": "TA 2", "code": "002-X-0000-000", "obligated_amount": 1000.0, }], }], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result # this agency has a record but the amounts are both 0, so we expect this return no results query_params = "?fiscal_year=2016" resp = client.get(url.format(code="010", query_params=query_params)) expected_result = { "fiscal_year": 2016, "toptier_code": "010", "messages": [ "Account data powering this endpoint were first collected in " "FY2017 Q2 under the DATA Act; as such, there are no data " "available for prior fiscal years." ], "page_metadata": { "hasNext": False, "hasPrevious": False, "next": None, "page": 1, "previous": None, "total": 0, "limit": 10, }, "results": [], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result
def test_federal_account_list_pagination(client, agency_account_data): query_params = f"?fiscal_year={current_fiscal_year()}&limit=2&page=1" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": True, "hasPrevious": False, "next": 2, "page": 1, "previous": None, "limit": 2, "total": 3, }, "results": [ { "gross_outlay_amount": 11100000.0, "name": "FA 1", "code": "001-0000", "obligated_amount": 111.0, "children": [{ "gross_outlay_amount": 11100000.0, "name": "TA 1", "code": "001-X-0000-000", "obligated_amount": 111.0, }], }, { "gross_outlay_amount": 100000.0, "name": "FA 3", "code": "003-0000", "obligated_amount": 100.0, "children": [{ "gross_outlay_amount": 100000.0, "name": "TA 6", "code": "003-2017/2018-0000-000", "obligated_amount": 100.0, }], }, ], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result query_params = f"?fiscal_year={current_fiscal_year()}&limit=2&page=2" resp = client.get(url.format(code="007", query_params=query_params)) expected_result = { "fiscal_year": current_fiscal_year(), "toptier_code": "007", "messages": [], "page_metadata": { "hasNext": False, "hasPrevious": True, "next": None, "page": 2, "previous": 1, "total": 3, "limit": 2, }, "results": [ { "gross_outlay_amount": 1000000.0, "name": "FA 2", "code": "002-0000", "obligated_amount": 10.0, "children": [{ "gross_outlay_amount": 1000000.0, "name": "TA 5", "code": "002-2008/2009-0000-000", "obligated_amount": 10.0, }], }, ], } assert resp.status_code == status.HTTP_200_OK assert resp.json() == expected_result
class UnlinkedAwards(AgencyBase): """Returns submission history of the specified agency for the specified fiscal year and period""" endpoint_doc = "usaspending_api/api_contracts/contracts/v2/reporting/agencies/toptier_code/fiscal_year/fiscal_period/unlinked_awards/type.md" annotation_options = { "assistance": { "unlinked_file_c_award_count": F("unlinked_assistance_c_awards"), "unlinked_file_d_award_count": F("unlinked_assistance_d_awards"), "total_linked_award_count": F("linked_assistance_awards"), }, "procurement": { "unlinked_file_c_award_count": F("unlinked_procurement_c_awards"), "unlinked_file_d_award_count": F("unlinked_procurement_d_awards"), "total_linked_award_count": F("linked_procurement_awards"), }, } tinyshield_model = [ { "key": "type", "name": "type", "type": "enum", "enum_values": ["assistance", "procurement"], "optional": False, "default": None, "allow_nulls": False, }, { "key": "fiscal_year", "name": "fiscal_year", "type": "integer", "min": fy(settings.API_SEARCH_MIN_DATE), "max": current_fiscal_year(), "optional": False, "default": None, "allow_nulls": False, }, { "key": "fiscal_period", "name": "fiscal_period", "type": "integer", "min": 2, "max": 12, "optional": False, "default": None, "allow_nulls": False, }, ] @cache_response() def get(self, request, toptier_code, fiscal_year, fiscal_period, type): my_request = { "type": type, "fiscal_year": fiscal_year, "fiscal_period": fiscal_period } validated = TinyShield(self.tinyshield_model).block(my_request) self.annotations = self.annotation_options[validated["type"]] self.fiscal_year = validated["fiscal_year"] self.fiscal_period = validated["fiscal_period"] return Response(self.get_unlinked_awards()) def get_unlinked_awards(self): result = (ReportingAgencyOverview.objects.filter( toptier_code=self.toptier_code, fiscal_year=self.fiscal_year, fiscal_period=self.fiscal_period).annotate( **self.annotations).values( "unlinked_file_c_award_count", "unlinked_file_d_award_count", "total_linked_award_count", ).first()) if not result: result = { "unlinked_file_c_award_count": 0, "unlinked_file_d_award_count": 0, "total_linked_award_count": 0, } return result