Merge branch 'master' into ui/request-approval-screen

This commit is contained in:
andrewdds 2018-07-26 12:28:50 -04:00 committed by GitHub
commit 9bbea99aa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 425 additions and 96 deletions

View File

@ -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
@ -98,6 +99,22 @@ def make_app(config, deps, **kwargs):
{"page": "request_approval"},
name="request_approval"
),
url(
r"/requests/verify/(\S+)",
RequestFinancialVerification,
{
"page": "financial_verification",
"requests_client": deps["requests_client"],
"fundz_client": deps["fundz_client"],
},
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"),

View File

@ -0,0 +1,75 @@
import tornado
from atst.handler import BaseHandler
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):
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(
self.application.default_router.reverse_url("financial_verification_submitted")
)
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
)

View File

@ -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

View File

@ -39,7 +39,8 @@
<tbody>
{% for r in requests %}
<tr>
<th scope="row"><a href="{{ reverse_url('request_form_update', 1, r['order_id']) }}">{{ r['order_id'] }}</a>
<th scope="row">
<a href="{{ reverse_url('request_form_update', 1, r['order_id']) if r["status"] != "approved" else reverse_url('financial_verification', r['order_id']) }}">{{ r['order_id'] }}</a>
{% if r['is_new'] %}<span class="usa-label">New</span>
</th>
{% end %}

View File

@ -0,0 +1,219 @@
{% extends "../base.html.to" %}
{% block content %}
<div class="col">
<div class="panel">
<div class="panel__content">
<div class="panel__heading">
<h1>Order #{{ request_id }}</h1>
<h2 id="financial-verification">Financial Verification</h2>
</div>
{% block form_action %}
<form method='POST' action="{{ reverse_url('financial_verification', request_id) }}" autocomplete="off">
{% end %}
{% module xsrf_form_html() %}
{% block form %}
{% autoescape None %}
{% if f.errors %}
<b class="usa-input-error-message">There were some errors, see below.</b>
{% end %}
<p class="usa-font-lead">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.</p>
{{ f.task_order_id.label }}
{{ f.task_order_id(placeholder="Example: 1234567899C0001") }}
{% for e in f.task_order_id.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.uii_ids.label }}
{{ f.uii_ids(placeholder="Example: \nDI 0CVA5786950 \nUN1945326361234786950") }}
{% for e in f.uii_ids.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.pe_id.label }}
{{ f.pe_id(placeholder="Example: 0203752A") }}
{% for e in f.pe_id.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.treasury_code.label }}
{{ f.treasury_code(placeholder="Example: 1200") }}
{% for e in f.treasury_code.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.ba_code.label }}
{{ f.ba_code(placeholder="Example: 02") }}
{% for e in f.ba_code.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
<!-- KO Information -->
<h3>Contracting Officer (KO) Information</h3>
{{ f.fname_co.label }}
{{ f.fname_co(placeholder="Contracting Officer first name") }}
{% for e in f.fname_co.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.lname_co.label }}
{{ f.lname_co(placeholder="Contracting Officer last name") }}
{% for e in f.lname_co.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.email_co.label }}
{{ f.email_co(placeholder="jane@mail.mil") }}
{% for e in f.email_co.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.office_co.label }}
{{ f.office_co(placeholder="Example: WHS") }}
{% for e in f.office_co.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
<!-- COR Information -->
<h3>Contracting Officer Representative (COR) Information</h3>
{{ f.fname_cor.label }}
{{ f.fname_cor(placeholder="Contracting Officer Representative first name") }}
{% for e in f.fname_cor.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.lname_cor.label }}
{{ f.lname_cor(placeholder="Contracting Officer Representative last name") }}
{% for e in f.lname_cor.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.email_cor.label }}
{{ f.email_cor(placeholder="jane@mail.mil") }}
{% for e in f.email_cor.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.office_cor.label }}
{{ f.office_cor(placeholder="Example: WHS") }}
{% for e in f.office_cor.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
<br><hr>
<em>&darr; FIELDS NEEDED FOR MANUAL ENTRY OF TASK ORDER INFORMATION (only necessary if EDA info not available)</em>
{{ f.funding_type.label }}
{{ f.funding_type }}
{% for e in f.funding_type.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.funding_type_other.label }}
{{ f.funding_type_other(placeholder="") }}
{% for e in f.funding_type_other.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.clin_0001.label }}
{{ f.clin_0001(placeholder="50,000") }}
{% for e in f.clin_0001.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.clin_0003.label }}
{{ f.clin_0003(placeholder="13,000") }}
{% for e in f.clin_0003.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.clin_1001.label }}
{{ f.clin_1001(placeholder="30,000") }}
{% for e in f.clin_1001.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.clin_1003.label }}
{{ f.clin_1003(placeholder="7,000") }}
{% for e in f.clin_1003.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.clin_2001.label }}
{{ f.clin_2001(placeholder="30,000") }}
{% for e in f.clin_2001.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{{ f.clin_2003.label }}
{{ f.clin_2003(placeholder="7,000") }}
{% for e in f.clin_2003.errors %}
<div class="usa-input-error-message">
{{ e }}
</div>
{% end %}
{% end %}
{% block next %}
<input type='submit' class='usa-button usa-button-primary' value='Save & Continue' />
{% end %}
</form>
</div>
</div>
</div>
{% end %}

View File

@ -0,0 +1,18 @@
{% extends "../base.html.to" %}
{% block content %}
<div class="col">
<div class="panel">
<div class="panel__content">
<div class="panel__heading">
<h2 id="financial-verification">Submitted</h2>
</div>
</div>
</div>
</div>
{% end %}

View File

@ -1,4 +1,4 @@
<div class="progress-menu progress-menu--five">
<div class="progress-menu progress-menu--four">
<ul>
{% for i,s in enumerate(screens) %}
<li class="progress-menu__item">

View File

@ -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/financial_verification_submitted"
@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/financial_verification_submitted"

View File

@ -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"

View File

@ -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):