import pytest from unittest.mock import MagicMock from flask import url_for import datetime from atst.eda_client import MockEDAClient from atst.routes.requests.financial_verification import ( GetFinancialVerificationForm, UpdateFinancialVerification, SaveFinancialVerificationDraft, ) from tests.mocks import MOCK_VALID_PE_ID from tests.factories import RequestFactory, UserFactory, LegacyTaskOrderFactory from atst.forms.exceptions import FormValidationError from atst.domain.requests.financial_verification import ( PENumberValidator, TaskOrderNumberValidator, ) from atst.models.request_status_event import RequestStatus from atst.models.attachment import Attachment from atst.domain.requests.query import RequestsQuery @pytest.fixture def fv_data(): return { "request-pe_id": "123", "legacy_task_order-number": MockEDAClient.MOCK_CONTRACT_NUMBER, "request-fname_co": "Contracting", "request-lname_co": "Officer", "request-email_co": "jane@mail.mil", "request-office_co": "WHS", "request-fname_cor": "Officer", "request-lname_cor": "Representative", "request-email_cor": "jane@mail.mil", "request-office_cor": "WHS", "request-uii_ids": "1234", "request-treasury_code": "00123456", "request-ba_code": "02A", } @pytest.fixture def e_fv_data(pdf_upload): return { "legacy_task_order-funding_type": "RDTE", "legacy_task_order-funding_type_other": "other", "legacy_task_order-expiration_date": "1/1/{}".format( datetime.date.today().year + 1 ), "legacy_task_order-clin_0001": "50000", "legacy_task_order-clin_0003": "13000", "legacy_task_order-clin_1001": "30000", "legacy_task_order-clin_1003": "7000", "legacy_task_order-clin_2001": "30000", "legacy_task_order-clin_2003": "7000", "legacy_task_order-pdf": pdf_upload, } MANUAL_TO_NUMBER = "DCA10096D0051" TrueValidator = MagicMock() TrueValidator.validate = MagicMock(return_value=True) FalseValidator = MagicMock() FalseValidator.validate = MagicMock(return_value=False) def test_update_fv(fv_data): request = RequestFactory.create() user = UserFactory.create() data = {**fv_data, "pe_id": MOCK_VALID_PE_ID} updated_request = UpdateFinancialVerification( TrueValidator, TrueValidator, user, request, data, is_extended=False ).execute() assert updated_request.is_pending_ccpo_approval def test_update_fv_re_enter_pe_number(fv_data): request = RequestFactory.create() user = UserFactory.create() data = {**fv_data, "pe_id": "0101228M"} update_fv = UpdateFinancialVerification( PENumberValidator(), TrueValidator, user, request, data, is_extended=False ) with pytest.raises(FormValidationError): update_fv.execute() updated_request = update_fv.execute() assert updated_request.is_pending_ccpo_approval def test_update_fv_invalid_task_order_number(fv_data): request = RequestFactory.create() user = UserFactory.create() data = {**fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER} update_fv = UpdateFinancialVerification( TrueValidator, TaskOrderNumberValidator(), user, request, data, is_extended=False, ) with pytest.raises(FormValidationError): update_fv.execute() def test_draft_without_pe_id(fv_data): request = RequestFactory.create() user = UserFactory.create() data = {"request-uii_ids": "1234"} assert SaveFinancialVerificationDraft( PENumberValidator(), TaskOrderNumberValidator(), user, request, data, is_extended=False, ).execute() def test_update_fv_extended(fv_data, e_fv_data): request = RequestFactory.create() user = UserFactory.create() data = {**fv_data, **e_fv_data} update_fv = UpdateFinancialVerification( TrueValidator, TaskOrderNumberValidator(), user, request, data, is_extended=True ) assert update_fv.execute() def test_update_fv_extended_does_not_validate_task_order(fv_data, e_fv_data): request = RequestFactory.create() user = UserFactory.create() data = {**fv_data, **e_fv_data, "legacy_task_order-number": "abc123"} update_fv = UpdateFinancialVerification( TrueValidator, TaskOrderNumberValidator(), user, request, data, is_extended=True ) assert update_fv.execute() def test_update_fv_missing_extended_data(fv_data): request = RequestFactory.create() user = UserFactory.create() update_fv = UpdateFinancialVerification( TrueValidator, TaskOrderNumberValidator(), user, request, fv_data, is_extended=True, ) with pytest.raises(FormValidationError): update_fv.execute() def test_update_fv_submission(fv_data): request = RequestFactory.create() user = UserFactory.create() updated_request = UpdateFinancialVerification( TrueValidator, TrueValidator, user, request, fv_data ).execute() assert updated_request def test_save_empty_draft(): request = RequestFactory.create() user = UserFactory.create() save_draft = SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, {}, is_extended=False ) assert save_draft.execute() def test_save_draft_with_ba_code(): request = RequestFactory.create() user = UserFactory.create() data = {"ba_code": "02A"} save_draft = SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, data, is_extended=False ) assert save_draft.execute() def test_save_draft_allows_invalid_data(): request = RequestFactory.create() user = UserFactory.create() data = { "legacy_task_order-number": MANUAL_TO_NUMBER, "request-pe_id": "123", "request-ba_code": "a", } assert SaveFinancialVerificationDraft( PENumberValidator(), TaskOrderNumberValidator(), user, request, data, is_extended=True, ).execute() def test_save_draft_and_then_submit(): request = RequestFactory.create() user = UserFactory.create() data = {"ba_code": "02A"} updated_request = SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, data, is_extended=False ).execute() with pytest.raises(FormValidationError): UpdateFinancialVerification( TrueValidator, TrueValidator, user, updated_request, data ).execute() def test_updated_request_has_pdf(fv_data, e_fv_data): request = RequestFactory.create() user = UserFactory.create() data = {**fv_data, **e_fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER} updated_request = UpdateFinancialVerification( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() assert updated_request.legacy_task_order.pdf def test_can_save_draft_with_just_pdf(e_fv_data): request = RequestFactory.create() user = UserFactory.create() data = {"legacy_task_order-pdf": e_fv_data["legacy_task_order-pdf"]} SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() form = GetFinancialVerificationForm(user, request, is_extended=True).execute() assert form.legacy_task_order.pdf def test_task_order_info_present_in_extended_form(fv_data, e_fv_data): request = RequestFactory.create() user = UserFactory.create() data = { "legacy_task_order-clin_0001": "1", "legacy_task_order-number": fv_data["legacy_task_order-number"], } SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() form = GetFinancialVerificationForm(user, request, is_extended=True).execute() assert form.legacy_task_order.clin_0001.data def test_update_ignores_empty_values(fv_data, e_fv_data): request = RequestFactory.create() user = UserFactory.create() data = {**fv_data, **e_fv_data, "legacy_task_order-funding_type": ""} SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() def test_can_save_draft_with_funding_type(fv_data, e_fv_data): request = RequestFactory.create() user = UserFactory.create() data = { "legacy_task_order-number": fv_data["legacy_task_order-number"], "legacy_task_order-funding_type": e_fv_data["legacy_task_order-funding_type"], } updated_request = SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, data, is_extended=False ).execute() assert updated_request.legacy_task_order.funding_type def test_update_fv_route(client, user_session, fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) user_session(user) response = client.post( url_for("requests.financial_verification", request_id=request.id), data=fv_data, follow_redirects=False, ) assert response.status_code == 200 def test_save_fv_draft_route(client, user_session, fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) user_session(user) response = client.post( url_for("requests.save_financial_verification_draft", request_id=request.id), data=fv_data, follow_redirects=True, ) assert response.status_code == 200 def test_get_fv_form_route(client, user_session, fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) user_session(user) response = client.get( url_for("requests.financial_verification", request_id=request.id), data=fv_data, follow_redirects=False, ) assert response.status_code == 200 def test_manual_task_order_triggers_extended_form( client, user_session, fv_data, e_fv_data ): user = UserFactory.create() request = RequestFactory.create(creator=user) data = {**fv_data, **e_fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER} UpdateFinancialVerification( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() user_session(user) response = client.get( url_for("requests.financial_verification", request_id=request.id), data=fv_data, follow_redirects=False, ) assert "extended" in response.headers["Location"] def test_manual_to_does_not_trigger_approval(client, user_session, fv_data, e_fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) data = { **fv_data, **e_fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER, "request-pe_id": "0101228N", } user_session(user) client.post( url_for( "requests.financial_verification", request_id=request.id, extended=True ), data=data, follow_redirects=True, ) updated_request = RequestsQuery.get(request.id) assert updated_request.status != RequestStatus.APPROVED def test_eda_task_order_does_trigger_approval(client, user_session, fv_data, e_fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) data = { **fv_data, **e_fv_data, "legacy_task_order-number": MockEDAClient.MOCK_CONTRACT_NUMBER, "request-pe_id": "0101228N", } user_session(user) client.post( url_for( "requests.financial_verification", request_id=request.id, extended=True ), data=data, follow_redirects=True, ) updated_request = RequestsQuery.get(request.id) assert updated_request.status == RequestStatus.APPROVED def test_attachment_on_non_extended_form(client, user_session, fv_data, e_fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) data = { **fv_data, **e_fv_data, "legacy_task_order-number": MockEDAClient.MOCK_CONTRACT_NUMBER, "request-pe_id": "0101228N", } user_session(user) client.post( url_for( "requests.financial_verification", request_id=request.id, extended=True ), data=data, follow_redirects=True, ) response = client.get( url_for("requests.financial_verification", request_id=request.id) ) assert response.status_code == 200 def test_task_order_number_persists_in_form(fv_data, e_fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) data = { **fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER, "request-pe_id": "0101228N", } try: UpdateFinancialVerification( TrueValidator, FalseValidator, user, request, data, is_extended=False ).execute() except FormValidationError: pass form = GetFinancialVerificationForm(user, request, is_extended=True).execute() assert form.legacy_task_order.number.data == MANUAL_TO_NUMBER def test_can_submit_once_to_details_are_entered(fv_data, e_fv_data): user = UserFactory.create() request = RequestFactory.create(creator=user) data = { **fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER, "request-pe_id": "0101228N", } try: UpdateFinancialVerification( TrueValidator, FalseValidator, user, request, data, is_extended=False ).execute() except FormValidationError: pass data = { **fv_data, **e_fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER, "request-pe_id": "0101228N", } assert UpdateFinancialVerification( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() def test_existing_task_order_with_pdf(fv_data, e_fv_data, client, user_session): # Use finver route to create initial TO #1, complete with PDF user = UserFactory.create() request = RequestFactory.create(creator=user) data = {**fv_data, **e_fv_data, "legacy_task_order-number": MANUAL_TO_NUMBER} UpdateFinancialVerification( TrueValidator, TaskOrderNumberValidator(), user, request, data, is_extended=True ).execute() # Save draft on a new finver form, but with same number as TO #1 user = UserFactory.create() request = RequestFactory.create(creator=user) data = {"legacy_task_order-number": MANUAL_TO_NUMBER} SaveFinancialVerificationDraft( TrueValidator, TaskOrderNumberValidator(), user, request, data, is_extended=False, ).execute() # Get finver form user_session(user) response = client.get( url_for("requests.financial_verification", request_id=request.id), follow_redirects=True, ) assert response.status_code == 200 def test_pdf_clearing(fv_data, e_fv_data, pdf_upload, pdf_upload2): user = UserFactory.create() request = RequestFactory.create(creator=user) data = {**fv_data, **e_fv_data, "legacy_task_order-pdf": pdf_upload} SaveFinancialVerificationDraft( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() data = {**data, "legacy_task_order-pdf": pdf_upload2} UpdateFinancialVerification( TrueValidator, TrueValidator, user, request, data, is_extended=True ).execute() form = GetFinancialVerificationForm(user, request, is_extended=True).execute() assert form.legacy_task_order.pdf.data == pdf_upload2.filename # TODO: This test manages an edge case for our current non-unique handling of # task orders. Because two requests can reference the same task order but we # only record one request ID on the PDF attachment, multiple task # orders/requests reference the same task order but only one of them is noted # in the related attachment entity. I have changed the handling in # FinancialVerificationBase#_get_form to be more generous in how it finds the # PDF filename and prepopulates the form data with that name. def test_always_derives_pdf_filename(fv_data, e_fv_data, pdf_upload): user = UserFactory.create() request_one = RequestFactory.create(creator=user) attachment = Attachment.attach( pdf_upload, resource="legacy_task_order", resource_id=request_one.id ) legacy_task_order = LegacyTaskOrderFactory.create(pdf=attachment) request_two = RequestFactory.create( creator=user, legacy_task_order=legacy_task_order ) form_one = GetFinancialVerificationForm( user, request_one, is_extended=True ).execute() form_two = GetFinancialVerificationForm( user, request_two, is_extended=True ).execute() assert form_one.legacy_task_order.pdf.data == attachment.filename assert form_two.legacy_task_order.pdf.data == attachment.filename