From c4f74ed437478d9694362bfe10ec839822377d6a Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Mon, 23 Jul 2018 15:12:22 -0400 Subject: [PATCH 01/11] Begin ripping out current financial step out of req process --- atst/app.py | 6 ++++++ templates/financial_verification.html.to | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 templates/financial_verification.html.to diff --git a/atst/app.py b/atst/app.py index 393edbc5..d1d5d5d6 100644 --- a/atst/app.py +++ b/atst/app.py @@ -91,6 +91,12 @@ def make_app(config, deps, **kwargs): {"requests_client": deps["requests_client"]}, name="requests_submit", ), + url( + r"/financial", + Main, + {"page": "financial_verification"}, + name="financial_verification", + ), url(r"/users", Main, {"page": "users"}, name="users"), url(r"/reports", Main, {"page": "reports"}, name="reports"), url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), diff --git a/templates/financial_verification.html.to b/templates/financial_verification.html.to new file mode 100644 index 00000000..f2ee22b0 --- /dev/null +++ b/templates/financial_verification.html.to @@ -0,0 +1,21 @@ +{% extends "base.html.to" %} + +{% block content %} + +
+ +
+ +
+ +
+

Order #36552512

+

Financial Verification

+
+ +
+
+
+ +{% end %} + From 899889f4ca1e8892a34b18cc0ea7cb9bdda9ac8c Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 23 Jul 2018 15:34:19 -0400 Subject: [PATCH 02/11] Show financial verification page when request is approved --- atst/app.py | 11 ++++-- .../request_financial_verification.py | 36 +++++++++++++++++++ templates/requests.html.to | 3 +- .../financial_verification.html.to | 2 +- 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 atst/handlers/request_financial_verification.py rename templates/{ => requests}/financial_verification.html.to (89%) diff --git a/atst/app.py b/atst/app.py index d1d5d5d6..19d2c901 100644 --- a/atst/app.py +++ b/atst/app.py @@ -9,6 +9,7 @@ from atst.handlers.root import Root from atst.handlers.login_redirect import LoginRedirect from atst.handlers.workspace import Workspace from atst.handlers.request import Request +from atst.handlers.request_financial_verification import RequestFinancialVerification from atst.handlers.request_new import RequestNew from atst.handlers.request_submit import RequestsSubmit from atst.handlers.dev import Dev @@ -92,9 +93,13 @@ def make_app(config, deps, **kwargs): name="requests_submit", ), url( - r"/financial", - Main, - {"page": "financial_verification"}, + r"/requests/verify/(\S+)", + RequestFinancialVerification, + { + "page": "financial_verification", + "requests_client": deps["requests_client"], + "fundz_client": deps["fundz_client"], + }, name="financial_verification", ), url(r"/users", Main, {"page": "users"}, name="users"), diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py new file mode 100644 index 00000000..51445d66 --- /dev/null +++ b/atst/handlers/request_financial_verification.py @@ -0,0 +1,36 @@ +import tornado +from collections import defaultdict + +from atst.handler import BaseHandler +from atst.forms.request import RequestForm +from atst.forms.org import OrgForm +from atst.forms.poc import POCForm +from atst.forms.review import ReviewForm +from atst.forms.financial import FinancialForm + + +class RequestFinancialVerification(BaseHandler): + def initialize(self, page, requests_client, fundz_client): + self.page = page + self.requests_client = requests_client + self.fundz_client = fundz_client + + @tornado.gen.coroutine + def get_existing_request(self, request_id): + if request_id is None: + return {} + request = yield self.requests_client.get("/requests/{}".format(request_id)) + return request.json + + @tornado.web.authenticated + @tornado.gen.coroutine + def get(self, request_id=None): + # self.check_xsrf_cookie() + # post_data = self.request.arguments + current_user = self.get_current_user() + existing_request = yield self.get_existing_request(request_id) + self.render( + "requests/financial_verification.html.to", + page=self.page, + ) + diff --git a/templates/requests.html.to b/templates/requests.html.to index 653c01b3..b56e806f 100644 --- a/templates/requests.html.to +++ b/templates/requests.html.to @@ -29,7 +29,8 @@ {% for r in requests %} - {{ r['order_id'] }} + + {{ r['order_id'] }} {% if r['is_new'] %}New {% end %} diff --git a/templates/financial_verification.html.to b/templates/requests/financial_verification.html.to similarity index 89% rename from templates/financial_verification.html.to rename to templates/requests/financial_verification.html.to index f2ee22b0..06abd2ea 100644 --- a/templates/financial_verification.html.to +++ b/templates/requests/financial_verification.html.to @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "../base.html.to" %} {% block content %} From 0112ff5cb20ac0e5eed78e87d2af94989584ff47 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 23 Jul 2018 16:11:54 -0400 Subject: [PATCH 03/11] Move financial verification to its own page --- .../request_financial_verification.py | 53 ++++- atst/handlers/request_new.py | 7 - .../requests/financial_verification.html.to | 204 +++++++++++++++++- tests/handlers/test_financial_verification.py | 84 ++++++++ tests/handlers/test_request_new.py | 88 +------- tests/mocks.py | 8 + 6 files changed, 339 insertions(+), 105 deletions(-) create mode 100644 tests/handlers/test_financial_verification.py diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index 51445d66..a3bf8fc8 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -1,11 +1,6 @@ import tornado -from collections import defaultdict from atst.handler import BaseHandler -from atst.forms.request import RequestForm -from atst.forms.org import OrgForm -from atst.forms.poc import POCForm -from atst.forms.review import ReviewForm from atst.forms.financial import FinancialForm @@ -25,12 +20,54 @@ class RequestFinancialVerification(BaseHandler): @tornado.web.authenticated @tornado.gen.coroutine def get(self, request_id=None): - # self.check_xsrf_cookie() - # post_data = self.request.arguments - current_user = self.get_current_user() existing_request = yield self.get_existing_request(request_id) + form = FinancialForm(data=existing_request['body'].get('financial_verification')) self.render( "requests/financial_verification.html.to", page=self.page, + f=form, + request_id=request_id, ) + @tornado.gen.coroutine + def update_request(self, request_id, form_data): + request_data = { + "creator_id": self.current_user["id"], + "request": {"financial_verification": form_data}, + } + response = yield self.requests_client.patch( + "/requests/{}".format(request_id), json=request_data + ) + return response + + @tornado.web.authenticated + @tornado.gen.coroutine + def post(self, request_id=None): + self.check_xsrf_cookie() + post_data = self.request.arguments + existing_request = yield self.get_existing_request(request_id) + form = FinancialForm(post_data) + + rerender_args = dict(request_id=request_id, f=form) + + if form.validate(): + response = yield self.update_request(request_id, form.data) + if response.ok: + valid = yield form.perform_extra_validation( + existing_request.get('body', {}).get('financial_verification'), + self.fundz_client + ) + if valid: + self.redirect('/requests') + else: + self.render( + "requests/financial_verification.html.to", + **rerender_args + ) + else: + self.set_status(response.code) + else: + self.render( + "requests/financial_verification.html.to", + **rerender_args + ) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 096572d3..de3c2713 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -6,7 +6,6 @@ from atst.forms.request import RequestForm from atst.forms.org import OrgForm from atst.forms.poc import POCForm from atst.forms.review import ReviewForm -from atst.forms.financial import FinancialForm class RequestNew(BaseHandler): @@ -221,12 +220,6 @@ class JEDIRequestFlow(object): "form": ReviewForm, "show":True, }, - { - "title": "Financial Verification", - "section": "financial_verification", - "form": FinancialForm, - "show": self.request and self.request["status"] == "approved", - }, ] @tornado.gen.coroutine diff --git a/templates/requests/financial_verification.html.to b/templates/requests/financial_verification.html.to index 06abd2ea..dc1c4d71 100644 --- a/templates/requests/financial_verification.html.to +++ b/templates/requests/financial_verification.html.to @@ -9,13 +9,211 @@
-

Order #36552512

-

Financial Verification

+

Order #{{ request_id }}

+

Financial Verification

+ {% block form_action %} +
+ {% end %} + + {% module xsrf_form_html() %} + {% block form %} + {% autoescape None %} + {% if f.errors %} + There were some errors, see below. + {% end %} + +

In order to get you access to the JEDI Cloud, we will need you to enter the details below that will help us verify and account for your Task Order.

+ + {{ f.task_order_id.label }} + {{ f.task_order_id(placeholder="Example: 1234567899C0001") }} + {% for e in f.task_order_id.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.uii_ids.label }} + {{ f.uii_ids(placeholder="Example: \nDI 0CVA5786950 \nUN1945326361234786950") }} + {% for e in f.uii_ids.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.pe_id.label }} + {{ f.pe_id(placeholder="Example: 0203752A") }} + {% for e in f.pe_id.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.treasury_code.label }} + {{ f.treasury_code(placeholder="Example: 1200") }} + {% for e in f.treasury_code.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.ba_code.label }} + {{ f.ba_code(placeholder="Example: 02") }} + {% for e in f.ba_code.errors %} +
+ {{ e }} +
+ {% end %} + + + +

Contracting Officer (KO) Information

+ + {{ f.fname_co.label }} + {{ f.fname_co(placeholder="Contracting Officer first name") }} + {% for e in f.fname_co.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.lname_co.label }} + {{ f.lname_co(placeholder="Contracting Officer last name") }} + {% for e in f.lname_co.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.email_co.label }} + {{ f.email_co(placeholder="jane@mail.mil") }} + {% for e in f.email_co.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.office_co.label }} + {{ f.office_co(placeholder="Example: WHS") }} + {% for e in f.office_co.errors %} +
+ {{ e }} +
+ {% end %} + + + + +

Contracting Officer Representative (COR) Information

+ + {{ f.fname_cor.label }} + {{ f.fname_cor(placeholder="Contracting Officer Representative first name") }} + {% for e in f.fname_cor.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.lname_cor.label }} + {{ f.lname_cor(placeholder="Contracting Officer Representative last name") }} + {% for e in f.lname_cor.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.email_cor.label }} + {{ f.email_cor(placeholder="jane@mail.mil") }} + {% for e in f.email_cor.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.office_cor.label }} + {{ f.office_cor(placeholder="Example: WHS") }} + {% for e in f.office_cor.errors %} +
+ {{ e }} +
+ {% end %} + +

+ ↓ FIELDS NEEDED FOR MANUAL ENTRY OF TASK ORDER INFORMATION (only necessary if EDA info not available) + + + {{ f.funding_type.label }} + {{ f.funding_type }} + {% for e in f.funding_type.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.funding_type_other.label }} + {{ f.funding_type_other(placeholder="") }} + {% for e in f.funding_type_other.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.clin_0001.label }} + {{ f.clin_0001(placeholder="50,000") }} + {% for e in f.clin_0001.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.clin_0003.label }} + {{ f.clin_0003(placeholder="13,000") }} + {% for e in f.clin_0003.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.clin_1001.label }} + {{ f.clin_1001(placeholder="30,000") }} + {% for e in f.clin_1001.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.clin_1003.label }} + {{ f.clin_1003(placeholder="7,000") }} + {% for e in f.clin_1003.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.clin_2001.label }} + {{ f.clin_2001(placeholder="30,000") }} + {% for e in f.clin_2001.errors %} +
+ {{ e }} +
+ {% end %} + + {{ f.clin_2003.label }} + {{ f.clin_2003(placeholder="7,000") }} + {% for e in f.clin_2003.errors %} +
+ {{ e }} +
+ {% end %} + {% end %} + {% block next %} + + {% end %} +
+
{% end %} - diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py new file mode 100644 index 00000000..4ca2ce2e --- /dev/null +++ b/tests/handlers/test_financial_verification.py @@ -0,0 +1,84 @@ +import re +import pytest +import tornado +import urllib +from tests.mocks import MOCK_REQUEST, MOCK_USER, MOCK_VALID_PE_ID + + +class TestPENumberInForm: + + required_data = { + "pe_id": "123", + "task_order_id": "1234567899C0001", + "fname_co": "Contracting", + "lname_co": "Officer", + "email_co": "jane@mail.mil", + "office_co": "WHS", + "fname_cor": "Officer", + "lname_cor": "Representative", + "email_cor": "jane@mail.mil", + "office_cor": "WHS", + "funding_type": "RDTE", + "funding_type_other": "other", + "clin_0001": "50,000", + "clin_0003": "13,000", + "clin_1001": "30,000", + "clin_1003": "7,000", + "clin_2001": "30,000", + "clin_2003": "7,000", + } + + def _set_monkeypatches(self, monkeypatch): + monkeypatch.setattr( + "atst.handlers.request_financial_verification.RequestFinancialVerification.get_current_user", lambda s: MOCK_USER + ) + monkeypatch.setattr( + "atst.handlers.request_financial_verification.RequestFinancialVerification.check_xsrf_cookie", lambda s: True + ) + monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) + + @tornado.gen.coroutine + def submit_data(self, http_client, base_url, data): + response = yield http_client.fetch( + base_url + "/requests/verify/{}".format(MOCK_REQUEST["id"]), + method="POST", + headers={"Content-Type": "application/x-www-form-urlencoded"}, + body=urllib.parse.urlencode(data), + follow_redirects=False, + raise_error=False, + ) + return response + + @pytest.mark.gen_test + def test_submit_request_form_with_invalid_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + response = yield self.submit_data(http_client, base_url, self.required_data) + + assert "We couldn\'t find that PE number" in response.body.decode() + assert response.code == 200 + assert "/requests/verify" in response.effective_url + + @pytest.mark.gen_test + def test_submit_request_form_with_unchanged_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + data = dict(self.required_data) + data['pe_id'] = MOCK_REQUEST['body']['financial_verification']['pe_id'] + + response = yield self.submit_data(http_client, base_url, data) + + assert response.code == 302 + assert response.headers.get("Location") == "/requests" + + @pytest.mark.gen_test + def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + data = dict(self.required_data) + data['pe_id'] = MOCK_VALID_PE_ID + + response = yield self.submit_data(http_client, base_url, data) + + assert response.code == 302 + assert response.headers.get("Location") == "/requests" diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 6a8a37f6..fc09cb3e 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -2,16 +2,9 @@ import re import pytest import tornado import urllib -from tests.mocks import MOCK_REQUEST, MOCK_VALID_PE_ID +from tests.mocks import MOCK_USER ERROR_CLASS = "usa-input-error-message" -MOCK_USER = { - "id": "9cb348f0-8102-4962-88c4-dac8180c904c", - "email": "fake.user@mail.com", - "first_name": "Fake", - "last_name": "User", -} - @pytest.mark.gen_test def test_submit_invalid_request_form(monkeypatch, http_client, base_url): @@ -50,82 +43,3 @@ def test_submit_valid_request_form(monkeypatch, http_client, base_url): body="meaning=42", ) assert "/requests/new/2" in response.effective_url - - -class TestPENumberInForm: - - required_data = { - "pe_id": "123", - "task_order_id": "1234567899C0001", - "fname_co": "Contracting", - "lname_co": "Officer", - "email_co": "jane@mail.mil", - "office_co": "WHS", - "fname_cor": "Officer", - "lname_cor": "Representative", - "email_cor": "jane@mail.mil", - "office_cor": "WHS", - "funding_type": "RDTE", - "funding_type_other": "other", - "clin_0001": "50,000", - "clin_0003": "13,000", - "clin_1001": "30,000", - "clin_1003": "7,000", - "clin_2001": "30,000", - "clin_2003": "7,000", - } - - def _set_monkeypatches(self, monkeypatch): - monkeypatch.setattr( - "atst.handlers.request_new.RequestNew.get_current_user", lambda s: MOCK_USER - ) - monkeypatch.setattr( - "atst.handlers.request_new.RequestNew.check_xsrf_cookie", lambda s: True - ) - monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) - - @tornado.gen.coroutine - def submit_data(self, http_client, base_url, data): - response = yield http_client.fetch( - base_url + "/requests/new/5/{}".format(MOCK_REQUEST["id"]), - method="POST", - headers={"Content-Type": "application/x-www-form-urlencoded"}, - body=urllib.parse.urlencode(data), - follow_redirects=False, - raise_error=False, - ) - return response - - @pytest.mark.gen_test - def test_submit_request_form_with_invalid_pe_id(self, monkeypatch, http_client, base_url): - self._set_monkeypatches(monkeypatch) - - response = yield self.submit_data(http_client, base_url, self.required_data) - - assert "We couldn\'t find that PE number" in response.body.decode() - assert response.code == 200 - assert "/requests/new/5" in response.effective_url - - @pytest.mark.gen_test - def test_submit_request_form_with_unchanged_pe_id(self, monkeypatch, http_client, base_url): - self._set_monkeypatches(monkeypatch) - - data = dict(self.required_data) - data['pe_id'] = MOCK_REQUEST['body']['financial_verification']['pe_id'] - - response = yield self.submit_data(http_client, base_url, data) - - assert response.code == 302 - assert response.headers.get("Location") == "/requests" - - @pytest.mark.gen_test - def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): - self._set_monkeypatches(monkeypatch) - - data = dict(self.required_data) - data['pe_id'] = MOCK_VALID_PE_ID - - response = yield self.submit_data(http_client, base_url, data) - - assert response.code == 302 - assert response.headers.get("Location") == "/requests" diff --git a/tests/mocks.py b/tests/mocks.py index 6cd3540c..a7290a03 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -4,6 +4,14 @@ from tornado.httpclient import HTTPRequest, HTTPResponse from atst.api_client import ApiClient +MOCK_USER = { + "id": "9cb348f0-8102-4962-88c4-dac8180c904c", + "email": "fake.user@mail.com", + "first_name": "Fake", + "last_name": "User", +} + + class MockApiClient(ApiClient): def __init__(self, service): From 27919e028122f26cb3596ada602b35275950ff82 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 23 Jul 2018 16:34:34 -0400 Subject: [PATCH 04/11] Redirect to interstitial submitted page --- atst/app.py | 6 ++++++ .../handlers/request_financial_verification.py | 4 +++- .../financial_verification_submitted.html.to | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 templates/requests/financial_verification_submitted.html.to diff --git a/atst/app.py b/atst/app.py index 19d2c901..bf6eb385 100644 --- a/atst/app.py +++ b/atst/app.py @@ -102,6 +102,12 @@ def make_app(config, deps, **kwargs): }, name="financial_verification", ), + url( + r"/requests/financial_verification_submitted", + Main, + {"page": "requests/financial_verification_submitted"}, + name="financial_verification_submitted", + ), url(r"/users", Main, {"page": "users"}, name="users"), url(r"/reports", Main, {"page": "reports"}, name="reports"), url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index a3bf8fc8..4c81f9d7 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -58,7 +58,9 @@ class RequestFinancialVerification(BaseHandler): self.fundz_client ) if valid: - self.redirect('/requests') + self.redirect( + self.application.default_router.reverse_url("financial_verification_submitted") + ) else: self.render( "requests/financial_verification.html.to", diff --git a/templates/requests/financial_verification_submitted.html.to b/templates/requests/financial_verification_submitted.html.to new file mode 100644 index 00000000..21088724 --- /dev/null +++ b/templates/requests/financial_verification_submitted.html.to @@ -0,0 +1,18 @@ +{% extends "../base.html.to" %} + +{% block content %} + +
+ +
+ +
+ +
+

Submitted

+
+
+
+
+ +{% end %} From b25e945d464be4f0d75d38f2e53ea7777732f0d3 Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 24 Jul 2018 10:32:37 -0400 Subject: [PATCH 05/11] Update menu progress to four steps --- templates/requests/menu.html.to | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/requests/menu.html.to b/templates/requests/menu.html.to index f7378753..4bc77431 100644 --- a/templates/requests/menu.html.to +++ b/templates/requests/menu.html.to @@ -1,4 +1,4 @@ -
+
    {% for i,s in enumerate(screens) %}
  • From e99b13347a1d1689eaaf3f6f2deecab0624c2f9f Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Mon, 23 Jul 2018 15:12:22 -0400 Subject: [PATCH 06/11] Begin ripping out current financial step out of req process --- atst/app.py | 6 ++++++ templates/financial_verification.html.to | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 templates/financial_verification.html.to diff --git a/atst/app.py b/atst/app.py index 393edbc5..d1d5d5d6 100644 --- a/atst/app.py +++ b/atst/app.py @@ -91,6 +91,12 @@ def make_app(config, deps, **kwargs): {"requests_client": deps["requests_client"]}, name="requests_submit", ), + url( + r"/financial", + Main, + {"page": "financial_verification"}, + name="financial_verification", + ), url(r"/users", Main, {"page": "users"}, name="users"), url(r"/reports", Main, {"page": "reports"}, name="reports"), url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), diff --git a/templates/financial_verification.html.to b/templates/financial_verification.html.to new file mode 100644 index 00000000..f2ee22b0 --- /dev/null +++ b/templates/financial_verification.html.to @@ -0,0 +1,21 @@ +{% extends "base.html.to" %} + +{% block content %} + +
    + +
    + +
    + +
    +

    Order #36552512

    +

    Financial Verification

    +
    + +
    +
    +
    + +{% end %} + From db0db3f32709ffaa1f92df031c5484bde5fc5c99 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 23 Jul 2018 15:34:19 -0400 Subject: [PATCH 07/11] Show financial verification page when request is approved --- atst/app.py | 11 ++++-- .../request_financial_verification.py | 36 +++++++++++++++++++ templates/requests.html.to | 3 +- .../financial_verification.html.to | 2 +- 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 atst/handlers/request_financial_verification.py rename templates/{ => requests}/financial_verification.html.to (89%) diff --git a/atst/app.py b/atst/app.py index d1d5d5d6..19d2c901 100644 --- a/atst/app.py +++ b/atst/app.py @@ -9,6 +9,7 @@ from atst.handlers.root import Root from atst.handlers.login_redirect import LoginRedirect from atst.handlers.workspace import Workspace from atst.handlers.request import Request +from atst.handlers.request_financial_verification import RequestFinancialVerification from atst.handlers.request_new import RequestNew from atst.handlers.request_submit import RequestsSubmit from atst.handlers.dev import Dev @@ -92,9 +93,13 @@ def make_app(config, deps, **kwargs): name="requests_submit", ), url( - r"/financial", - Main, - {"page": "financial_verification"}, + r"/requests/verify/(\S+)", + RequestFinancialVerification, + { + "page": "financial_verification", + "requests_client": deps["requests_client"], + "fundz_client": deps["fundz_client"], + }, name="financial_verification", ), url(r"/users", Main, {"page": "users"}, name="users"), diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py new file mode 100644 index 00000000..51445d66 --- /dev/null +++ b/atst/handlers/request_financial_verification.py @@ -0,0 +1,36 @@ +import tornado +from collections import defaultdict + +from atst.handler import BaseHandler +from atst.forms.request import RequestForm +from atst.forms.org import OrgForm +from atst.forms.poc import POCForm +from atst.forms.review import ReviewForm +from atst.forms.financial import FinancialForm + + +class RequestFinancialVerification(BaseHandler): + def initialize(self, page, requests_client, fundz_client): + self.page = page + self.requests_client = requests_client + self.fundz_client = fundz_client + + @tornado.gen.coroutine + def get_existing_request(self, request_id): + if request_id is None: + return {} + request = yield self.requests_client.get("/requests/{}".format(request_id)) + return request.json + + @tornado.web.authenticated + @tornado.gen.coroutine + def get(self, request_id=None): + # self.check_xsrf_cookie() + # post_data = self.request.arguments + current_user = self.get_current_user() + existing_request = yield self.get_existing_request(request_id) + self.render( + "requests/financial_verification.html.to", + page=self.page, + ) + diff --git a/templates/requests.html.to b/templates/requests.html.to index 653c01b3..b56e806f 100644 --- a/templates/requests.html.to +++ b/templates/requests.html.to @@ -29,7 +29,8 @@ {% for r in requests %} - {{ r['order_id'] }} + + {{ r['order_id'] }} {% if r['is_new'] %}New {% end %} diff --git a/templates/financial_verification.html.to b/templates/requests/financial_verification.html.to similarity index 89% rename from templates/financial_verification.html.to rename to templates/requests/financial_verification.html.to index f2ee22b0..06abd2ea 100644 --- a/templates/financial_verification.html.to +++ b/templates/requests/financial_verification.html.to @@ -1,4 +1,4 @@ -{% extends "base.html.to" %} +{% extends "../base.html.to" %} {% block content %} From c8e10261653228ed3e2b94827e18d357d874d535 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 23 Jul 2018 16:11:54 -0400 Subject: [PATCH 08/11] Move financial verification to its own page --- .../request_financial_verification.py | 53 ++++- atst/handlers/request_new.py | 7 - .../requests/financial_verification.html.to | 204 +++++++++++++++++- tests/handlers/test_financial_verification.py | 84 ++++++++ tests/handlers/test_request_new.py | 88 +------- tests/mocks.py | 8 + 6 files changed, 339 insertions(+), 105 deletions(-) create mode 100644 tests/handlers/test_financial_verification.py diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index 51445d66..a3bf8fc8 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -1,11 +1,6 @@ import tornado -from collections import defaultdict from atst.handler import BaseHandler -from atst.forms.request import RequestForm -from atst.forms.org import OrgForm -from atst.forms.poc import POCForm -from atst.forms.review import ReviewForm from atst.forms.financial import FinancialForm @@ -25,12 +20,54 @@ class RequestFinancialVerification(BaseHandler): @tornado.web.authenticated @tornado.gen.coroutine def get(self, request_id=None): - # self.check_xsrf_cookie() - # post_data = self.request.arguments - current_user = self.get_current_user() existing_request = yield self.get_existing_request(request_id) + form = FinancialForm(data=existing_request['body'].get('financial_verification')) self.render( "requests/financial_verification.html.to", page=self.page, + f=form, + request_id=request_id, ) + @tornado.gen.coroutine + def update_request(self, request_id, form_data): + request_data = { + "creator_id": self.current_user["id"], + "request": {"financial_verification": form_data}, + } + response = yield self.requests_client.patch( + "/requests/{}".format(request_id), json=request_data + ) + return response + + @tornado.web.authenticated + @tornado.gen.coroutine + def post(self, request_id=None): + self.check_xsrf_cookie() + post_data = self.request.arguments + existing_request = yield self.get_existing_request(request_id) + form = FinancialForm(post_data) + + rerender_args = dict(request_id=request_id, f=form) + + if form.validate(): + response = yield self.update_request(request_id, form.data) + if response.ok: + valid = yield form.perform_extra_validation( + existing_request.get('body', {}).get('financial_verification'), + self.fundz_client + ) + if valid: + self.redirect('/requests') + else: + self.render( + "requests/financial_verification.html.to", + **rerender_args + ) + else: + self.set_status(response.code) + else: + self.render( + "requests/financial_verification.html.to", + **rerender_args + ) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 096572d3..de3c2713 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -6,7 +6,6 @@ from atst.forms.request import RequestForm from atst.forms.org import OrgForm from atst.forms.poc import POCForm from atst.forms.review import ReviewForm -from atst.forms.financial import FinancialForm class RequestNew(BaseHandler): @@ -221,12 +220,6 @@ class JEDIRequestFlow(object): "form": ReviewForm, "show":True, }, - { - "title": "Financial Verification", - "section": "financial_verification", - "form": FinancialForm, - "show": self.request and self.request["status"] == "approved", - }, ] @tornado.gen.coroutine diff --git a/templates/requests/financial_verification.html.to b/templates/requests/financial_verification.html.to index 06abd2ea..dc1c4d71 100644 --- a/templates/requests/financial_verification.html.to +++ b/templates/requests/financial_verification.html.to @@ -9,13 +9,211 @@
    -

    Order #36552512

    -

    Financial Verification

    +

    Order #{{ request_id }}

    +

    Financial Verification

    + {% block form_action %} +
    + {% end %} + + {% module xsrf_form_html() %} + {% block form %} + {% autoescape None %} + {% if f.errors %} + There were some errors, see below. + {% end %} + +

    In order to get you access to the JEDI Cloud, we will need you to enter the details below that will help us verify and account for your Task Order.

    + + {{ f.task_order_id.label }} + {{ f.task_order_id(placeholder="Example: 1234567899C0001") }} + {% for e in f.task_order_id.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.uii_ids.label }} + {{ f.uii_ids(placeholder="Example: \nDI 0CVA5786950 \nUN1945326361234786950") }} + {% for e in f.uii_ids.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.pe_id.label }} + {{ f.pe_id(placeholder="Example: 0203752A") }} + {% for e in f.pe_id.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.treasury_code.label }} + {{ f.treasury_code(placeholder="Example: 1200") }} + {% for e in f.treasury_code.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.ba_code.label }} + {{ f.ba_code(placeholder="Example: 02") }} + {% for e in f.ba_code.errors %} +
    + {{ e }} +
    + {% end %} + + + +

    Contracting Officer (KO) Information

    + + {{ f.fname_co.label }} + {{ f.fname_co(placeholder="Contracting Officer first name") }} + {% for e in f.fname_co.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.lname_co.label }} + {{ f.lname_co(placeholder="Contracting Officer last name") }} + {% for e in f.lname_co.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.email_co.label }} + {{ f.email_co(placeholder="jane@mail.mil") }} + {% for e in f.email_co.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.office_co.label }} + {{ f.office_co(placeholder="Example: WHS") }} + {% for e in f.office_co.errors %} +
    + {{ e }} +
    + {% end %} + + + + +

    Contracting Officer Representative (COR) Information

    + + {{ f.fname_cor.label }} + {{ f.fname_cor(placeholder="Contracting Officer Representative first name") }} + {% for e in f.fname_cor.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.lname_cor.label }} + {{ f.lname_cor(placeholder="Contracting Officer Representative last name") }} + {% for e in f.lname_cor.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.email_cor.label }} + {{ f.email_cor(placeholder="jane@mail.mil") }} + {% for e in f.email_cor.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.office_cor.label }} + {{ f.office_cor(placeholder="Example: WHS") }} + {% for e in f.office_cor.errors %} +
    + {{ e }} +
    + {% end %} + +

    + ↓ FIELDS NEEDED FOR MANUAL ENTRY OF TASK ORDER INFORMATION (only necessary if EDA info not available) + + + {{ f.funding_type.label }} + {{ f.funding_type }} + {% for e in f.funding_type.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.funding_type_other.label }} + {{ f.funding_type_other(placeholder="") }} + {% for e in f.funding_type_other.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.clin_0001.label }} + {{ f.clin_0001(placeholder="50,000") }} + {% for e in f.clin_0001.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.clin_0003.label }} + {{ f.clin_0003(placeholder="13,000") }} + {% for e in f.clin_0003.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.clin_1001.label }} + {{ f.clin_1001(placeholder="30,000") }} + {% for e in f.clin_1001.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.clin_1003.label }} + {{ f.clin_1003(placeholder="7,000") }} + {% for e in f.clin_1003.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.clin_2001.label }} + {{ f.clin_2001(placeholder="30,000") }} + {% for e in f.clin_2001.errors %} +
    + {{ e }} +
    + {% end %} + + {{ f.clin_2003.label }} + {{ f.clin_2003(placeholder="7,000") }} + {% for e in f.clin_2003.errors %} +
    + {{ e }} +
    + {% end %} + {% end %} + {% block next %} + + {% end %} +
    +
{% end %} - diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py new file mode 100644 index 00000000..4ca2ce2e --- /dev/null +++ b/tests/handlers/test_financial_verification.py @@ -0,0 +1,84 @@ +import re +import pytest +import tornado +import urllib +from tests.mocks import MOCK_REQUEST, MOCK_USER, MOCK_VALID_PE_ID + + +class TestPENumberInForm: + + required_data = { + "pe_id": "123", + "task_order_id": "1234567899C0001", + "fname_co": "Contracting", + "lname_co": "Officer", + "email_co": "jane@mail.mil", + "office_co": "WHS", + "fname_cor": "Officer", + "lname_cor": "Representative", + "email_cor": "jane@mail.mil", + "office_cor": "WHS", + "funding_type": "RDTE", + "funding_type_other": "other", + "clin_0001": "50,000", + "clin_0003": "13,000", + "clin_1001": "30,000", + "clin_1003": "7,000", + "clin_2001": "30,000", + "clin_2003": "7,000", + } + + def _set_monkeypatches(self, monkeypatch): + monkeypatch.setattr( + "atst.handlers.request_financial_verification.RequestFinancialVerification.get_current_user", lambda s: MOCK_USER + ) + monkeypatch.setattr( + "atst.handlers.request_financial_verification.RequestFinancialVerification.check_xsrf_cookie", lambda s: True + ) + monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) + + @tornado.gen.coroutine + def submit_data(self, http_client, base_url, data): + response = yield http_client.fetch( + base_url + "/requests/verify/{}".format(MOCK_REQUEST["id"]), + method="POST", + headers={"Content-Type": "application/x-www-form-urlencoded"}, + body=urllib.parse.urlencode(data), + follow_redirects=False, + raise_error=False, + ) + return response + + @pytest.mark.gen_test + def test_submit_request_form_with_invalid_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + response = yield self.submit_data(http_client, base_url, self.required_data) + + assert "We couldn\'t find that PE number" in response.body.decode() + assert response.code == 200 + assert "/requests/verify" in response.effective_url + + @pytest.mark.gen_test + def test_submit_request_form_with_unchanged_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + data = dict(self.required_data) + data['pe_id'] = MOCK_REQUEST['body']['financial_verification']['pe_id'] + + response = yield self.submit_data(http_client, base_url, data) + + assert response.code == 302 + assert response.headers.get("Location") == "/requests" + + @pytest.mark.gen_test + def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + data = dict(self.required_data) + data['pe_id'] = MOCK_VALID_PE_ID + + response = yield self.submit_data(http_client, base_url, data) + + assert response.code == 302 + assert response.headers.get("Location") == "/requests" diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 6a8a37f6..fc09cb3e 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -2,16 +2,9 @@ import re import pytest import tornado import urllib -from tests.mocks import MOCK_REQUEST, MOCK_VALID_PE_ID +from tests.mocks import MOCK_USER ERROR_CLASS = "usa-input-error-message" -MOCK_USER = { - "id": "9cb348f0-8102-4962-88c4-dac8180c904c", - "email": "fake.user@mail.com", - "first_name": "Fake", - "last_name": "User", -} - @pytest.mark.gen_test def test_submit_invalid_request_form(monkeypatch, http_client, base_url): @@ -50,82 +43,3 @@ def test_submit_valid_request_form(monkeypatch, http_client, base_url): body="meaning=42", ) assert "/requests/new/2" in response.effective_url - - -class TestPENumberInForm: - - required_data = { - "pe_id": "123", - "task_order_id": "1234567899C0001", - "fname_co": "Contracting", - "lname_co": "Officer", - "email_co": "jane@mail.mil", - "office_co": "WHS", - "fname_cor": "Officer", - "lname_cor": "Representative", - "email_cor": "jane@mail.mil", - "office_cor": "WHS", - "funding_type": "RDTE", - "funding_type_other": "other", - "clin_0001": "50,000", - "clin_0003": "13,000", - "clin_1001": "30,000", - "clin_1003": "7,000", - "clin_2001": "30,000", - "clin_2003": "7,000", - } - - def _set_monkeypatches(self, monkeypatch): - monkeypatch.setattr( - "atst.handlers.request_new.RequestNew.get_current_user", lambda s: MOCK_USER - ) - monkeypatch.setattr( - "atst.handlers.request_new.RequestNew.check_xsrf_cookie", lambda s: True - ) - monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) - - @tornado.gen.coroutine - def submit_data(self, http_client, base_url, data): - response = yield http_client.fetch( - base_url + "/requests/new/5/{}".format(MOCK_REQUEST["id"]), - method="POST", - headers={"Content-Type": "application/x-www-form-urlencoded"}, - body=urllib.parse.urlencode(data), - follow_redirects=False, - raise_error=False, - ) - return response - - @pytest.mark.gen_test - def test_submit_request_form_with_invalid_pe_id(self, monkeypatch, http_client, base_url): - self._set_monkeypatches(monkeypatch) - - response = yield self.submit_data(http_client, base_url, self.required_data) - - assert "We couldn\'t find that PE number" in response.body.decode() - assert response.code == 200 - assert "/requests/new/5" in response.effective_url - - @pytest.mark.gen_test - def test_submit_request_form_with_unchanged_pe_id(self, monkeypatch, http_client, base_url): - self._set_monkeypatches(monkeypatch) - - data = dict(self.required_data) - data['pe_id'] = MOCK_REQUEST['body']['financial_verification']['pe_id'] - - response = yield self.submit_data(http_client, base_url, data) - - assert response.code == 302 - assert response.headers.get("Location") == "/requests" - - @pytest.mark.gen_test - def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): - self._set_monkeypatches(monkeypatch) - - data = dict(self.required_data) - data['pe_id'] = MOCK_VALID_PE_ID - - response = yield self.submit_data(http_client, base_url, data) - - assert response.code == 302 - assert response.headers.get("Location") == "/requests" diff --git a/tests/mocks.py b/tests/mocks.py index 6cd3540c..a7290a03 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -4,6 +4,14 @@ from tornado.httpclient import HTTPRequest, HTTPResponse from atst.api_client import ApiClient +MOCK_USER = { + "id": "9cb348f0-8102-4962-88c4-dac8180c904c", + "email": "fake.user@mail.com", + "first_name": "Fake", + "last_name": "User", +} + + class MockApiClient(ApiClient): def __init__(self, service): From 609597c0ad417c73138edcd603ecc51d82ab0429 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 23 Jul 2018 16:34:34 -0400 Subject: [PATCH 09/11] Redirect to interstitial submitted page --- atst/app.py | 6 ++++++ .../handlers/request_financial_verification.py | 4 +++- .../financial_verification_submitted.html.to | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 templates/requests/financial_verification_submitted.html.to diff --git a/atst/app.py b/atst/app.py index 19d2c901..bf6eb385 100644 --- a/atst/app.py +++ b/atst/app.py @@ -102,6 +102,12 @@ def make_app(config, deps, **kwargs): }, name="financial_verification", ), + url( + r"/requests/financial_verification_submitted", + Main, + {"page": "requests/financial_verification_submitted"}, + name="financial_verification_submitted", + ), url(r"/users", Main, {"page": "users"}, name="users"), url(r"/reports", Main, {"page": "reports"}, name="reports"), url(r"/calculator", Main, {"page": "calculator"}, name="calculator"), diff --git a/atst/handlers/request_financial_verification.py b/atst/handlers/request_financial_verification.py index a3bf8fc8..4c81f9d7 100644 --- a/atst/handlers/request_financial_verification.py +++ b/atst/handlers/request_financial_verification.py @@ -58,7 +58,9 @@ class RequestFinancialVerification(BaseHandler): self.fundz_client ) if valid: - self.redirect('/requests') + self.redirect( + self.application.default_router.reverse_url("financial_verification_submitted") + ) else: self.render( "requests/financial_verification.html.to", diff --git a/templates/requests/financial_verification_submitted.html.to b/templates/requests/financial_verification_submitted.html.to new file mode 100644 index 00000000..21088724 --- /dev/null +++ b/templates/requests/financial_verification_submitted.html.to @@ -0,0 +1,18 @@ +{% extends "../base.html.to" %} + +{% block content %} + +
+ +
+ +
+ +
+

Submitted

+
+
+
+
+ +{% end %} From 5dcea3895cce81e0c2a44c3c04e3bf6d767ed162 Mon Sep 17 00:00:00 2001 From: Luis Cielak Date: Tue, 24 Jul 2018 10:32:37 -0400 Subject: [PATCH 10/11] Update menu progress to four steps --- templates/requests/menu.html.to | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/requests/menu.html.to b/templates/requests/menu.html.to index f7378753..4bc77431 100644 --- a/templates/requests/menu.html.to +++ b/templates/requests/menu.html.to @@ -1,4 +1,4 @@ -
+
    {% for i,s in enumerate(screens) %}
  • From 73d50a369ed6d1fcc59478576725ab931cfb9971 Mon Sep 17 00:00:00 2001 From: dandds Date: Thu, 26 Jul 2018 09:00:13 -0400 Subject: [PATCH 11/11] update financial verification tests --- tests/handlers/test_financial_verification.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/handlers/test_financial_verification.py b/tests/handlers/test_financial_verification.py index 4ca2ce2e..6e60bb4e 100644 --- a/tests/handlers/test_financial_verification.py +++ b/tests/handlers/test_financial_verification.py @@ -69,7 +69,7 @@ class TestPENumberInForm: response = yield self.submit_data(http_client, base_url, data) assert response.code == 302 - assert response.headers.get("Location") == "/requests" + assert response.headers.get("Location") == "/requests/financial_verification_submitted" @pytest.mark.gen_test def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): @@ -81,4 +81,4 @@ class TestPENumberInForm: response = yield self.submit_data(http_client, base_url, data) assert response.code == 302 - assert response.headers.get("Location") == "/requests" + assert response.headers.get("Location") == "/requests/financial_verification_submitted"