ccpo can submit basic review
This commit is contained in:
parent
15713d78a4
commit
c123cdd6e9
22
atst/forms/ccpo_review.py
Normal file
22
atst/forms/ccpo_review.py
Normal file
@ -0,0 +1,22 @@
|
||||
from wtforms.fields.html5 import EmailField, TelField
|
||||
from wtforms.fields import StringField, TextAreaField
|
||||
from wtforms.validators import Required, Email
|
||||
|
||||
from .forms import ValidatedForm
|
||||
from .validators import Alphabet, PhoneNumber
|
||||
|
||||
|
||||
class CCPOReviewForm(ValidatedForm):
|
||||
comments = TextAreaField(
|
||||
"Comments",
|
||||
description="Add notes or comments explaining what changes are being requested or why further discussion is needed about this request.",
|
||||
)
|
||||
fname_mao = StringField("First Name", validators=[Required(), Alphabet()])
|
||||
lname_mao = StringField("Last Name", validators=[Required(), Alphabet()])
|
||||
email_mao = EmailField("Mission Owner e-mail (optional)", validators=[Email()])
|
||||
phone_mao = TelField(
|
||||
"Mission Owner phone number (optional)",
|
||||
validators=[Required(), PhoneNumber()],
|
||||
)
|
||||
fname_ccpo = StringField("First Name", validators=[Required(), Alphabet()])
|
||||
lname_ccpo = StringField("Last Name", validators=[Required(), Alphabet()])
|
@ -1,10 +1,11 @@
|
||||
from flask import render_template, g, Response
|
||||
from flask import render_template, g, Response, request as http_request, redirect, url_for
|
||||
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
|
||||
|
||||
|
||||
def task_order_dictionary(task_order):
|
||||
@ -15,11 +16,7 @@ def task_order_dictionary(task_order):
|
||||
}
|
||||
|
||||
|
||||
@requests_bp.route("/requests/approval/<string:request_id>", methods=["GET"])
|
||||
def approval(request_id):
|
||||
request = Requests.get(g.current_user, request_id)
|
||||
Authorization.check_can_approve_request(g.current_user)
|
||||
|
||||
def render_approval(request, form=None):
|
||||
data = request.body
|
||||
if request.task_order:
|
||||
data["task_order"] = task_order_dictionary(request.task_order)
|
||||
@ -27,13 +24,35 @@ def approval(request_id):
|
||||
return render_template(
|
||||
"requests/approval.html",
|
||||
data=data,
|
||||
request_id=request_id,
|
||||
request_id=request.id,
|
||||
status=request.status.value,
|
||||
financial_review=True,
|
||||
pdf_available=request.task_order and request.task_order.pdf,
|
||||
f=form or CCPOReviewForm(),
|
||||
)
|
||||
|
||||
|
||||
@requests_bp.route("/requests/approval/<string:request_id>", methods=["GET"])
|
||||
def approval(request_id):
|
||||
request = Requests.get(g.current_user, request_id)
|
||||
Authorization.check_can_approve_request(g.current_user)
|
||||
|
||||
return render_approval(request)
|
||||
|
||||
|
||||
@requests_bp.route("/requests/submit_approval/<string:request_id>", methods=["POST"])
|
||||
def submit_approval(request_id):
|
||||
request = Requests.get(g.current_user, request_id)
|
||||
Authorization.check_can_approve_request(g.current_user)
|
||||
|
||||
form = CCPOReviewForm(http_request.form)
|
||||
if form.validate():
|
||||
Requests.approve_for_financial_verification(request, form.data)
|
||||
return redirect(url_for("requests.requests_index"))
|
||||
else:
|
||||
return render_approval(request, form)
|
||||
|
||||
|
||||
@requests_bp.route("/requests/task_order_download/<string:request_id>", methods=["GET"])
|
||||
def task_order_pdf_download(request_id):
|
||||
request = Requests.get(g.current_user, request_id)
|
||||
|
@ -2,12 +2,14 @@
|
||||
|
||||
{% from "components/icon.html" import Icon %}
|
||||
{% from "components/alert.html" import Alert %}
|
||||
{% from "components/text_input.html" import TextInput %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<article class='col col--grow request-approval'>
|
||||
|
||||
<form>
|
||||
<form method="POST" action="{{ url_for("requests.submit_approval", request_id=request_id) }}" autocomplete="off">
|
||||
{{ f.csrf_token }}
|
||||
<section class='panel'>
|
||||
<header class='panel__heading request-approval__heading'>
|
||||
<h1 class='h2'>Request #{{ request_id }}</h1>
|
||||
@ -58,21 +60,11 @@
|
||||
<div class='form-row'>
|
||||
|
||||
<div class='form-col form-col--half'>
|
||||
|
||||
<div class='usa-input'>
|
||||
<label for='mo-behalf-fname'>First Name</label>
|
||||
<input id='mo-behalf-fname' type='text' placeholder='First name of mission authorizing official' />
|
||||
</div>
|
||||
|
||||
{{ TextInput(f.fname_mao, placeholder="First name of mission authorizing official") }}
|
||||
</div>
|
||||
|
||||
<div class='form-col form-col--half'>
|
||||
|
||||
<div class='usa-input'>
|
||||
<label for='mo-behalf-lname'>Last Name</label>
|
||||
<input id='mo-behalf-lname' type='text' placeholder='Last name of mission authorizing official'/>
|
||||
</div>
|
||||
|
||||
{{ TextInput(f.lname_mao, placeholder="Last name of mission authorizing official") }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -80,23 +72,12 @@
|
||||
<div class='form-row'>
|
||||
|
||||
<div class='form-col form-col--half'>
|
||||
|
||||
|
||||
<div class='usa-input'>
|
||||
<label for='mo-behalf-email'>Mission Owner e-mail (optional)</label>
|
||||
<input id='mo-behalf-email' type='email' placeholder='name@mail.mil'/>
|
||||
</div>
|
||||
|
||||
{{ TextInput(f.email_mao, placeholder="name@mail.mil") }}
|
||||
</div>
|
||||
|
||||
|
||||
<div class='form-col form-col--half'>
|
||||
|
||||
<div class='usa-input'>
|
||||
<label for='mo-behalf-phone'>Mission Owner phone number (optional)</label>
|
||||
<input id='mo-behalf-phone' type='tel' placeholder='(123) 456-7890'/>
|
||||
</div>
|
||||
|
||||
{{ TextInput(f.phone_mao, placeholder="(123) 456-7890", validation='usPhone') }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -107,21 +88,11 @@
|
||||
<div class='form-row'>
|
||||
|
||||
<div class='form-col form-col--half'>
|
||||
|
||||
<div class='usa-input'>
|
||||
<label for='ccpo-behalf-fname'>First Name</label>
|
||||
<input id='ccpo-behalf-fname' type='text' placeholder='First name of CCPO authorizing official' />
|
||||
</div>
|
||||
|
||||
{{ TextInput(f.fname_ccpo, placeholder="First name of CCPO authorizing official") }}
|
||||
</div>
|
||||
|
||||
<div class='form-col form-col--half'>
|
||||
|
||||
<div class='usa-input'>
|
||||
<label for='ccpo-behalf-lname'>Last Name</label>
|
||||
<input id='ccpo-behalf-lname' type='text' placeholder='Last name of CCPO authorizing official'/>
|
||||
</div>
|
||||
|
||||
{{ TextInput(f.lname_ccpo, placeholder="Last name of CCPO authorizing official") }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -135,12 +106,7 @@
|
||||
<div class='form-row'>
|
||||
|
||||
<div class='form-col'>
|
||||
|
||||
<div class='usa-input'>
|
||||
<label for='notes'>Internal Comments <em>(optional)</em></label>
|
||||
<textarea id='notes' placeholder='Add notes or comments for internal CCPO reference.'/></textarea>
|
||||
</div>
|
||||
|
||||
{{ TextInput(f.comments, paragraph=True, placeholder="Add notes or comments for internal CCPO reference.") }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -150,7 +116,7 @@
|
||||
</section>
|
||||
|
||||
<section class='action-group'>
|
||||
<a href='#' class='usa-button usa-button-big'>Approve Request</a>
|
||||
<button type="submit" class='usa-button usa-button-big'>Approve Request</button>
|
||||
<a href='#' class='usa-button usa-button-big usa-button-secondary'>Mark as Changes Requested</a>
|
||||
<a href='#' class='icon-link'>
|
||||
{{ Icon('x') }}
|
||||
|
@ -70,7 +70,7 @@ class RequestReviewFactory(Base):
|
||||
fname_mao = factory.Faker("first_name")
|
||||
lname_mao = factory.Faker("last_name")
|
||||
email_mao = factory.Faker("email")
|
||||
phone_mao = factory.Faker("phone_number")
|
||||
phone_mao = factory.LazyFunction(lambda: "".join(random.choices(string.digits, k=10)))
|
||||
fname_ccpo = factory.Faker("first_name")
|
||||
lname_ccpo = factory.Faker("last_name")
|
||||
|
||||
|
@ -4,7 +4,9 @@ from flask import url_for
|
||||
from atst.models.attachment import Attachment
|
||||
from atst.domain.roles import Roles
|
||||
|
||||
from tests.factories import RequestFactory, TaskOrderFactory, UserFactory
|
||||
from tests.factories import (
|
||||
RequestFactory, TaskOrderFactory, UserFactory, RequestReviewFactory
|
||||
)
|
||||
|
||||
|
||||
def test_ccpo_can_view_approval(user_session, client):
|
||||
@ -59,3 +61,14 @@ def test_task_order_download_does_not_exist(client, user_session):
|
||||
url_for("requests.task_order_pdf_download", request_id=request.id)
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_can_submit_request_approval(client, user_session):
|
||||
user = UserFactory.from_atat_role("ccpo")
|
||||
user_session(user)
|
||||
request = RequestFactory.create()
|
||||
review_data = RequestReviewFactory.dictionary()
|
||||
response = client.post(
|
||||
url_for("requests.submit_approval", request_id=request.id), data=review_data
|
||||
)
|
||||
assert response.status_code == 301
|
||||
|
Loading…
x
Reference in New Issue
Block a user