diff --git a/atst/domain/requests.py b/atst/domain/requests.py index f87a8382..47629ebc 100644 --- a/atst/domain/requests.py +++ b/atst/domain/requests.py @@ -58,17 +58,31 @@ class Requests(object): return False @classmethod - def get(cls, user, request_id): + def _get(cls, user, request_id): try: request = db.session.query(Request).filter_by(id=request_id).one() except (NoResultFound, exc.DataError): raise NotFoundError("request") + return request + + @classmethod + def get(cls, user, request_id): + request = Requests._get(user, request_id) + if not Authorization.can_view_request(user, request): raise UnauthorizedError(user, "get request") return request + @classmethod + def get_for_approval(cls, user, request_id): + request = Requests._get(user, request_id) + + Authorization.check_can_approve_request(user) + + return request + @classmethod def get_many(cls, creator=None): filters = [] @@ -281,13 +295,19 @@ WHERE requests_with_status.status = :status return request @classmethod - def accept_for_financial_verification(cls, user, request, review_data): - Requests.set_status(request, RequestStatus.PENDING_FINANCIAL_VERIFICATION) + def advance(cls, user, request, review_data): + if request.status == RequestStatus.PENDING_CCPO_ACCEPTANCE: + Requests.set_status(request, RequestStatus.PENDING_FINANCIAL_VERIFICATION) + elif request.status == RequestStatus.PENDING_CCPO_APPROVAL: + Requests.approve_and_create_workspace(request) return Requests._add_review(user, request, review_data) @classmethod def request_changes(cls, user, request, review_data): - Requests.set_status(request, RequestStatus.CHANGES_REQUESTED) + if request.status == RequestStatus.PENDING_CCPO_ACCEPTANCE: + Requests.set_status(request, RequestStatus.CHANGES_REQUESTED) + elif request.status == RequestStatus.PENDING_CCPO_APPROVAL: + Requests.set_status(request, RequestStatus.CHANGES_REQUESTED_TO_FINVER) return Requests._add_review(user, request, review_data) diff --git a/atst/models/request_status_event.py b/atst/models/request_status_event.py index 15e8a3d1..283633b1 100644 --- a/atst/models/request_status_event.py +++ b/atst/models/request_status_event.py @@ -16,9 +16,10 @@ class RequestStatus(Enum): PENDING_CCPO_ACCEPTANCE = "Pending CCPO Acceptance" PENDING_CCPO_APPROVAL = "Pending CCPO Approval" CHANGES_REQUESTED = "Changes Requested" + CHANGES_REQUESTED_TO_FINVER = "Change Requested to Financial Verification" APPROVED = "Approved" EXPIRED = "Expired" - CANCELED = "Canceled" + DELETED = "Deleted" class RequestStatusEvent(Base): diff --git a/atst/routes/requests/approval.py b/atst/routes/requests/approval.py index ebb4126e..de67fba4 100644 --- a/atst/routes/requests/approval.py +++ b/atst/routes/requests/approval.py @@ -11,7 +11,6 @@ from flask import current_app as app from . import requests_bp from atst.domain.requests import Requests from atst.domain.exceptions import NotFoundError -from atst.domain.authz import Authorization from atst.forms.ccpo_review import CCPOReviewForm @@ -47,23 +46,19 @@ def render_approval(request, form=None): @requests_bp.route("/requests/approval/", methods=["GET"]) def approval(request_id): - request = Requests.get(g.current_user, request_id) - Authorization.check_can_approve_request(g.current_user) + request = Requests.get_for_approval(g.current_user, request_id) return render_approval(request) @requests_bp.route("/requests/submit_approval/", methods=["POST"]) def submit_approval(request_id): - request = Requests.get(g.current_user, request_id) - Authorization.check_can_approve_request(g.current_user) + request = Requests.get_for_approval(g.current_user, request_id) form = CCPOReviewForm(http_request.form) if form.validate(): if http_request.form.get("approved"): - Requests.accept_for_financial_verification( - g.current_user, request, form.data - ) + Requests.advance(g.current_user, request, form.data) else: Requests.request_changes(g.current_user, request, form.data) diff --git a/tests/domain/test_requests.py b/tests/domain/test_requests.py index 34045076..bb4d8949 100644 --- a/tests/domain/test_requests.py +++ b/tests/domain/test_requests.py @@ -181,12 +181,43 @@ def test_set_status_sets_revision(): assert request.latest_revision == request.status_events[-1].revision -def test_accept_for_financial_verification(): - request = RequestFactory.create() - review_data = RequestReviewFactory.dictionary() - Requests.accept_for_financial_verification( - UserFactory.create(), request, review_data +def test_advance_to_financial_verification(): + request = RequestFactory.create_with_status( + status=RequestStatus.PENDING_CCPO_ACCEPTANCE ) + review_data = RequestReviewFactory.dictionary() + Requests.advance(UserFactory.create(), request, review_data) assert request.status == RequestStatus.PENDING_FINANCIAL_VERIFICATION current_review = request.latest_status.review assert current_review.fname_mao == review_data["fname_mao"] + + +def test_advance_to_approval(): + request = RequestFactory.create_with_status( + status=RequestStatus.PENDING_CCPO_APPROVAL + ) + review_data = RequestReviewFactory.dictionary() + Requests.advance(UserFactory.create(), request, review_data) + assert request.status == RequestStatus.APPROVED + + +def test_request_changes_to_request_application(): + request = RequestFactory.create_with_status( + status=RequestStatus.PENDING_CCPO_ACCEPTANCE + ) + review_data = RequestReviewFactory.dictionary() + Requests.request_changes(UserFactory.create(), request, review_data) + assert request.status == RequestStatus.CHANGES_REQUESTED + current_review = request.latest_status.review + assert current_review.fname_mao == review_data["fname_mao"] + + +def test_request_changes_to_financial_verification_info(): + request = RequestFactory.create_with_status( + status=RequestStatus.PENDING_CCPO_APPROVAL + ) + review_data = RequestReviewFactory.dictionary() + Requests.request_changes(UserFactory.create(), request, review_data) + assert request.status == RequestStatus.CHANGES_REQUESTED_TO_FINVER + current_review = request.latest_status.review + assert current_review.fname_mao == review_data["fname_mao"] diff --git a/tests/factories.py b/tests/factories.py index ad8cb048..ab6e964a 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -148,6 +148,14 @@ class RequestFactory(Base): return RequestRevisionFactory.build(**data) + @classmethod + def create_with_status(cls, status=RequestStatus.STARTED, **kwargs): + request = RequestFactory(**kwargs) + RequestStatusEventFactory.create( + request=request, revision=request.latest_revision, new_status=status + ) + return request + class PENumberFactory(Base): class Meta: diff --git a/tests/models/test_requests.py b/tests/models/test_requests.py index a5bbef93..f1409481 100644 --- a/tests/models/test_requests.py +++ b/tests/models/test_requests.py @@ -65,9 +65,9 @@ def test_request_status_pending_expired_displayname(): def test_request_status_pending_deleted_displayname(): request = RequestFactory.create() - request = Requests.set_status(request, RequestStatus.CANCELED) + request = Requests.set_status(request, RequestStatus.DELETED) - assert request.status_displayname == "Canceled" + assert request.status_displayname == "Deleted" def test_annual_spend(): diff --git a/tests/routes/test_request_approval.py b/tests/routes/test_request_approval.py index ced46240..ec110eb1 100644 --- a/tests/routes/test_request_approval.py +++ b/tests/routes/test_request_approval.py @@ -10,6 +10,7 @@ from tests.factories import ( TaskOrderFactory, UserFactory, RequestReviewFactory, + RequestStatusEventFactory, ) @@ -70,7 +71,9 @@ def test_task_order_download_does_not_exist(client, user_session): def test_can_submit_request_approval(client, user_session): user = UserFactory.from_atat_role("ccpo") user_session(user) - request = RequestFactory.create() + request = RequestFactory.create_with_status( + status=RequestStatus.PENDING_CCPO_ACCEPTANCE + ) review_data = RequestReviewFactory.dictionary() review_data["approved"] = True response = client.post( @@ -83,7 +86,9 @@ def test_can_submit_request_approval(client, user_session): def test_can_submit_request_denial(client, user_session): user = UserFactory.from_atat_role("ccpo") user_session(user) - request = RequestFactory.create() + request = RequestFactory.create_with_status( + status=RequestStatus.PENDING_CCPO_ACCEPTANCE + ) review_data = RequestReviewFactory.dictionary() review_data["denied"] = True response = client.post(