Refactor fv form to separate TO from request

This commit is contained in:
richard-dds 2018-10-22 22:16:39 -04:00
parent 1606bad016
commit 0439525f0f
9 changed files with 295 additions and 329 deletions

View File

@ -82,9 +82,7 @@ class Requests(object):
revision = create_revision_from_request_body(new_body) revision = create_revision_from_request_body(new_body)
request.revisions.append(revision) request.revisions.append(revision)
request = RequestsQuery.add_and_commit(request) return RequestsQuery.add_and_commit(request)
return request
@classmethod @classmethod
def approve_and_create_workspace(cls, request): def approve_and_create_workspace(cls, request):
@ -160,29 +158,10 @@ class Requests(object):
def update_financial_verification(cls, request_id, financial_data, task_order=None): def update_financial_verification(cls, request_id, financial_data, task_order=None):
request = RequestsQuery.get_with_lock(request_id) request = RequestsQuery.get_with_lock(request_id)
delta = pick(
[
"uii_ids",
"pe_id",
"treasury_code",
"ba_code",
"fname_co",
"lname_co",
"email_co",
"office_co",
"fname_cor",
"lname_cor",
"email_cor",
"office_cor",
],
financial_data,
)
if task_order: if task_order:
request.task_order = task_order request.task_order = task_order
request = Requests._update(request, {"financial_verification": delta}) request = Requests._update(request, {"financial_verification": financial_data})
return request return request
@classmethod @classmethod

View File

@ -19,14 +19,14 @@ class TaskOrders(object):
) )
except NoResultFound: except NoResultFound:
if TaskOrders._client(): if TaskOrders._client():
task_order = TaskOrders._get_from_eda(order_number) task_order = TaskOrders.get_from_eda(order_number)
else: else:
raise NotFoundError("task_order") raise NotFoundError("task_order")
return task_order return task_order
@classmethod @classmethod
def _get_from_eda(cls, order_number): def get_from_eda(cls, order_number):
to_data = TaskOrders._client().get_contract(order_number, status="y") to_data = TaskOrders._client().get_contract(order_number, status="y")
if to_data: if to_data:
# TODO: we need to determine exactly what we're getting and storing from the EDA client # TODO: we need to determine exactly what we're getting and storing from the EDA client
@ -38,9 +38,9 @@ class TaskOrders(object):
raise NotFoundError("task_order") raise NotFoundError("task_order")
@classmethod @classmethod
def create(cls, **kwargs): def create(cls, source=Source.MANUAL, **kwargs):
to_data = drop(["source"], kwargs) to_data = {k: v for k, v in kwargs.items() if v not in ["", None]}
task_order = TaskOrder(source=Source.MANUAL, **to_data) task_order = TaskOrder(source=source, **to_data)
db.session.add(task_order) db.session.add(task_order)
db.session.commit() db.session.commit()
@ -51,33 +51,6 @@ class TaskOrders(object):
def _client(cls): def _client(cls):
return app.eda_client return app.eda_client
@classmethod
def get_or_create_task_order(cls, number, task_order_data=None):
try:
return TaskOrders.get(number)
except NotFoundError:
if task_order_data:
pdf_file = task_order_data.pop("pdf")
# should catch the error here
attachment = Attachment.attach(pdf_file)
return TaskOrders.create(
**task_order_data,
number=number,
source=Source.MANUAL,
pdf=attachment,
)
@classmethod
def get_or_create(cls, number, attachment=None, data=None):
try:
return TaskOrders.get(number)
except NotFoundError:
data = data or {}
return TaskOrders.create(
**data, number=number, pdf=attachment, source=Source.MANUAL
)
@classmethod @classmethod
def update(cls, task_order, dct): def update(cls, task_order, dct):
updated = update_obj(task_order, dct) updated = update_obj(task_order, dct)

View File

@ -1,7 +1,7 @@
import re import re
import pendulum import pendulum
from wtforms.fields.html5 import DateField, EmailField from wtforms.fields.html5 import DateField, EmailField
from wtforms.fields import StringField, FileField from wtforms.fields import StringField, FileField, FormField
from wtforms.validators import InputRequired, Email, Regexp, Optional from wtforms.validators import InputRequired, Email, Regexp, Optional
from flask_wtf.file import FileAllowed from flask_wtf.file import FileAllowed
@ -21,17 +21,16 @@ def number_to_int(num):
return int(num) return int(num)
class BaseFinancialForm(ValidatedForm): def coerce_choice(val):
def reset(self): if val is None:
""" return None
Reset UII info so that it can be de-parsed rendered properly. elif isinstance(val, str):
This is a stupid workaround, and there's probably a better way. return val
""" else:
self.uii_ids.process_data(self.uii_ids.data) return val.value
def validate(self, **kwargs):
return super().validate()
class DraftValidateMixin(object):
def validate_draft(self): def validate_draft(self):
""" """
Another stupid workaround. Maybe there isn't a better way. Another stupid workaround. Maybe there isn't a better way.
@ -49,86 +48,19 @@ class BaseFinancialForm(ValidatedForm):
return valid return valid
@property
def is_missing_task_order_number(self):
return False
task_order_number = StringField( class TaskOrderForm(ValidatedForm, DraftValidateMixin):
number = StringField(
"Task Order Number associated with this request", "Task Order Number associated with this request",
description="Include the original Task Order number (including the 000X at the end). Do not include any modification numbers. Note that there may be a lag between approving a task order and when it becomes available in our system.", description="Include the original Task Order number (including the 000X at the end). Do not include any modification numbers. Note that there may be a lag between approving a task order and when it becomes available in our system.",
validators=[InputRequired()], validators=[InputRequired()],
) )
uii_ids = NewlineListField(
"Unique Item Identifier (UII)s related to your application(s) if you already have them.",
description="If you have more than one UII, place each one on a new line.",
)
pe_id = StringField(
"Program Element Number",
description="PE numbers help the Department of Defense identify which offices' budgets are contributing towards this resource use. <br/><em>It should be 7 digits followed by 1-3 letters, and should have a zero as the first and third digits.</em>",
validators=[InputRequired()],
)
treasury_code = StringField(
"Program Treasury Code",
description="Program Treasury Code (or Appropriations Code) identifies resource types. <br/> <em>It should be a four digit or six digit number, optionally prefixed by one or more zeros.</em>",
validators=[InputRequired(), Regexp(TREASURY_CODE_REGEX)],
)
ba_code = StringField(
"Program Budget Activity (BA) Code",
description="BA Code is used to identify the purposes, projects, or types of activities financed by the appropriation fund. <br/><em>It should be two digits, followed by an optional letter.</em>",
validators=[InputRequired(), Regexp(BA_CODE_REGEX)],
)
fname_co = StringField("KO First Name", validators=[InputRequired()])
lname_co = StringField("KO Last Name", validators=[InputRequired()])
email_co = EmailField("KO Email", validators=[InputRequired(), Email()])
office_co = StringField("KO Office", validators=[InputRequired()])
fname_cor = StringField("COR First Name", validators=[InputRequired()])
lname_cor = StringField("COR Last Name", validators=[InputRequired()])
email_cor = EmailField("COR Email", validators=[InputRequired(), Email()])
office_cor = StringField("COR Office", validators=[InputRequired()])
class FinancialForm(BaseFinancialForm):
@property
def is_missing_task_order_number(self):
return "task_order_number" in self.errors
@property
def is_only_missing_task_order_number(self):
return "task_order_number" in self.errors and len(self.errors) == 1
class ExtendedFinancialForm(BaseFinancialForm):
def validate(self, *args, **kwargs):
if self.funding_type.data == "OTHER":
self.funding_type_other.validators.append(InputRequired())
to_validator = None
if kwargs.get("has_attachment"):
to_validators = list(self.task_order.validators)
self.task_order.validators = []
valid = super().validate(*args, **kwargs)
if to_validator:
self.task_order.validators = to_validators
return valid
funding_type = SelectField( funding_type = SelectField(
description="What is the source of funding?", description="What is the source of funding?",
choices=FUNDING_TYPES, choices=FUNDING_TYPES,
validators=[InputRequired()], validators=[InputRequired()],
coerce=coerce_choice,
render_kw={"required": False}, render_kw={"required": False},
) )
@ -190,7 +122,7 @@ class ExtendedFinancialForm(BaseFinancialForm):
filters=[number_to_int], filters=[number_to_int],
) )
task_order = FileField( pdf = FileField(
"Upload a copy of your Task Order", "Upload a copy of your Task Order",
validators=[ validators=[
FileAllowed(["pdf"], "Only PDF documents can be uploaded."), FileAllowed(["pdf"], "Only PDF documents can be uploaded."),
@ -198,3 +130,101 @@ class ExtendedFinancialForm(BaseFinancialForm):
], ],
render_kw={"required": False}, render_kw={"required": False},
) )
class RequestFinancialVerificationForm(ValidatedForm, DraftValidateMixin):
uii_ids = NewlineListField(
"Unique Item Identifier (UII)s related to your application(s) if you already have them.",
description="If you have more than one UII, place each one on a new line.",
)
pe_id = StringField(
"Program Element Number",
description="PE numbers help the Department of Defense identify which offices' budgets are contributing towards this resource use. <br/><em>It should be 7 digits followed by 1-3 letters, and should have a zero as the first and third digits.</em>",
validators=[InputRequired()],
)
treasury_code = StringField(
"Program Treasury Code",
description="Program Treasury Code (or Appropriations Code) identifies resource types. <br/> <em>It should be a four digit or six digit number, optionally prefixed by one or more zeros.</em>",
validators=[InputRequired(), Regexp(TREASURY_CODE_REGEX)],
)
ba_code = StringField(
"Program Budget Activity (BA) Code",
description="BA Code is used to identify the purposes, projects, or types of activities financed by the appropriation fund. <br/><em>It should be two digits, followed by an optional letter.</em>",
validators=[InputRequired(), Regexp(BA_CODE_REGEX)],
)
fname_co = StringField("KO First Name", validators=[InputRequired()])
lname_co = StringField("KO Last Name", validators=[InputRequired()])
email_co = EmailField("KO Email", validators=[InputRequired(), Email()])
office_co = StringField("KO Office", validators=[InputRequired()])
fname_cor = StringField("COR First Name", validators=[InputRequired()])
lname_cor = StringField("COR Last Name", validators=[InputRequired()])
email_cor = EmailField("COR Email", validators=[InputRequired(), Email()])
office_cor = StringField("COR Office", validators=[InputRequired()])
def reset(self):
"""
Reset UII info so that it can be de-parsed rendered properly.
This is a stupid workaround, and there's probably a better way.
"""
self.uii_ids.process_data(self.uii_ids.data)
class FinancialVerificationForm(ValidatedForm):
task_order = FormField(TaskOrderForm)
request = FormField(RequestFinancialVerificationForm)
def validate(self, *args, **kwargs):
if self.task_order.funding_type.data == "OTHER":
self.task_order.funding_type_other.validators.append(InputRequired())
to_number_validators = None
if kwargs.get("has_attachment"):
to_number_validators = list(self.task_order.number.validators)
self.task_order.number.validators = []
valid = super().validate()
if to_number_validators:
self.task_order.number.validators = to_number_validators
return valid
def do_validate_request(self):
"""
Called do_validate_request to avoid being considered an inline
validator by wtforms.
"""
return self.request.validate(self)
def validate_draft(self):
return self.task_order.validate_draft() and self.request.validate_draft()
def reset(self):
self.request.reset()
@property
def pe_id(self):
return self.request.pe_id
@property
def task_order_number(self):
return self.task_order.number
@property
def is_missing_task_order_number(self):
return "number" in self.errors.get("task_order", {})
@property
def is_only_missing_task_order_number(self):
return "task_order_number" in self.errors and len(self.errors) == 1

View File

@ -4,7 +4,7 @@ from werkzeug.datastructures import ImmutableMultiDict, FileStorage
from . import requests_bp from . import requests_bp
from atst.domain.requests import Requests from atst.domain.requests import Requests
from atst.forms.financial import FinancialForm, ExtendedFinancialForm from atst.forms.financial import FinancialVerificationForm
from atst.forms.exceptions import FormValidationError from atst.forms.exceptions import FormValidationError
from atst.domain.exceptions import NotFoundError from atst.domain.exceptions import NotFoundError
from atst.domain.requests.financial_verification import ( from atst.domain.requests.financial_verification import (
@ -13,52 +13,42 @@ from atst.domain.requests.financial_verification import (
) )
from atst.models.attachment import Attachment from atst.models.attachment import Attachment
from atst.domain.task_orders import TaskOrders from atst.domain.task_orders import TaskOrders
from atst.utils import getattr_path
def fv_extended(_http_request): def fv_extended(_http_request):
return _http_request.args.get("extended", "false").lower() in ["true", "t"] return _http_request.args.get("extended", "false").lower() in ["true", "t"]
class FinancialVerification(object):
def __init__(self, request):
self.request = request.latest_revision
self.task_order = request.task_order
class FinancialVerificationBase(object): class FinancialVerificationBase(object):
def _get_form(self, request, is_extended, formdata=None): def _get_form(self, request, is_extended, formdata=None):
existing_fv_data = request.financial_verification _formdata = ImmutableMultiDict(formdata) if formdata is not None else None
fv = FinancialVerification(request)
if request.task_order: form = FinancialVerificationForm(obj=fv, formdata=_formdata)
task_order_dict = request.task_order.to_dictionary()
task_order_dict.update(
{
"task_order_number": request.task_order.number,
"funding_type": getattr_path(
request, "task_order.funding_type.value"
),
}
)
existing_fv_data = {**existing_fv_data, **task_order_dict}
mdict = ImmutableMultiDict(formdata) if formdata is not None else None
if is_extended: if is_extended:
try: try:
attachment = Attachment.get_for_resource("task_order", self.request.id) attachment = Attachment.get_for_resource("task_order", self.request.id)
existing_fv_data["task_order"] = attachment.filename form.task_order.pdf.data = attachment.filename
except NotFoundError: except NotFoundError:
pass pass
return ExtendedFinancialForm(formdata=mdict, data=existing_fv_data) return form
else:
return FinancialForm(formdata=mdict, data=existing_fv_data)
def _process_attachment(self, is_extended, form): def _process_attachment(self, is_extended, form):
attachment = None attachment = None
if is_extended: if is_extended:
attachment = None attachment = None
if isinstance(form.task_order.data, FileStorage): if isinstance(form.task_order.pdf.data, FileStorage):
Attachment.delete_for_resource("task_order", self.request.id) Attachment.delete_for_resource("task_order", self.request.id)
attachment = Attachment.attach( attachment = Attachment.attach(
form.task_order.data, "task_order", self.request.id form.task_order.pdf.data, "task_order", self.request.id
) )
elif isinstance(form.task_order.data, str): elif isinstance(form.task_order.pdf.data, str):
try: try:
attachment = Attachment.get_for_resource( attachment = Attachment.get_for_resource(
"task_order", self.request.id "task_order", self.request.id
@ -67,23 +57,16 @@ class FinancialVerificationBase(object):
pass pass
if attachment: if attachment:
form.task_order.data = attachment.filename form.task_order.pdf.data = attachment.filename
return attachment return attachment
def _try_create_task_order(self, form, attachment): def _try_create_task_order(self, form, attachment):
form_data = form.data task_order_number = form.task_order.number.data
task_order_number = form_data.pop("task_order_number")
if not task_order_number: if not task_order_number:
return None return None
task_order_data = { task_order_data = form.task_order.data
k: v for (k, v) in form_data.items() if k in TaskOrders.TASK_ORDER_DATA
}
task_order_data["number"] = task_order_number
funding_type = form_data.get("funding_type")
task_order_data["funding_type"] = funding_type if funding_type != "" else None
if attachment: if attachment:
task_order_data["pdf"] = attachment task_order_data["pdf"] = attachment
@ -96,7 +79,7 @@ class FinancialVerificationBase(object):
pass pass
try: try:
return TaskOrders._get_from_eda(task_order_number) return TaskOrders.get_from_eda(task_order_number)
except NotFoundError: except NotFoundError:
pass pass
@ -156,8 +139,11 @@ class UpdateFinancialVerification(FinancialVerificationBase):
attachment = self._process_attachment(self.is_extended, form) attachment = self._process_attachment(self.is_extended, form)
if not form.validate(has_attachment=attachment): if self.is_extended:
should_update = False if not form.validate(has_attachment=attachment):
should_update = False
else:
should_update = form.do_validate_request()
if not self.pe_validator.validate(self.request, form.pe_id.data): if not self.pe_validator.validate(self.request, form.pe_id.data):
self._apply_pe_number_error(form.pe_id) self._apply_pe_number_error(form.pe_id)
@ -170,7 +156,7 @@ class UpdateFinancialVerification(FinancialVerificationBase):
if should_update: if should_update:
task_order = self._try_create_task_order(form, attachment) task_order = self._try_create_task_order(form, attachment)
updated_request = Requests.update_financial_verification( updated_request = Requests.update_financial_verification(
self.request.id, form.data, task_order=task_order self.request.id, form.request.data, task_order=task_order
) )
if should_submit: if should_submit:
return Requests.submit_financial_verification(updated_request) return Requests.submit_financial_verification(updated_request)
@ -217,7 +203,7 @@ class SaveFinancialVerificationDraft(FinancialVerificationBase):
attachment = self._process_attachment(self.is_extended, form) attachment = self._process_attachment(self.is_extended, form)
task_order = self._try_create_task_order(form, attachment) task_order = self._try_create_task_order(form, attachment)
updated_request = Requests.update_financial_verification( updated_request = Requests.update_financial_verification(
self.request.id, form.data, task_order=task_order self.request.id, form.request.data, task_order=task_order
) )
if valid: if valid:

View File

@ -32,7 +32,7 @@ export default {
computed: { computed: {
showTaskOrder: function() { showTaskOrder: function() {
return !this.initialData.task_order || this.shouldForceShowTaskOrder return this.initialData.task_order.number || this.shouldForceShowTaskOrder
} }
}, },

View File

@ -68,55 +68,55 @@
{% if extended %} {% if extended %}
<fieldset class="form__sub-fields form__sub-fields--warning"> <fieldset class="form__sub-fields form__sub-fields--warning">
{{ OptionsInput(f.funding_type) }} {{ OptionsInput(f.task_order.funding_type) }}
<template v-if="funding_type == 'OTHER'" v-cloak> <template v-if="funding_type == 'OTHER'" v-cloak>
{{ TextInput(f.funding_type_other) }} {{ TextInput(f.task_order.funding_type_other) }}
</template> </template>
{{ DateInput(f.expiration_date, placeholder='MM / DD / YYYY', validation='date', tooltip='Please enter the expiration date for the task order only and do not include options that you may choose to exercise in the future.') }} {{ DateInput(f.task_order.expiration_date, placeholder='MM / DD / YYYY', validation='date', tooltip='Please enter the expiration date for the task order only and do not include options that you may choose to exercise in the future.') }}
{{ TextInput( {{ TextInput(
f.clin_0001, f.task_order.clin_0001,
validation='dollars' validation='dollars'
) }} ) }}
{{ TextInput( {{ TextInput(
f.clin_0003, f.task_order.clin_0003,
validation='dollars' validation='dollars'
) }} ) }}
{{ TextInput( {{ TextInput(
f.clin_1001, f.task_order.clin_1001,
validation='dollars' validation='dollars'
) }} ) }}
{{ TextInput( {{ TextInput(
f.clin_1003, f.task_order.clin_1003,
validation='dollars' validation='dollars'
) }} ) }}
{{ TextInput( {{ TextInput(
f.clin_2001, f.task_order.clin_2001,
validation='dollars' validation='dollars'
) }} ) }}
{{ TextInput( {{ TextInput(
f.clin_2003, f.task_order.clin_2003,
validation='dollars' validation='dollars'
) }} ) }}
<template v-if="showTaskOrder"> <template v-if="showTaskOrder">
<div class="usa-input {% if f.task_order.errors %} usa-input--error {% endif %}"> <div class="usa-input {% if f.task_order.pdf.errors %} usa-input--error {% endif %}">
{{ f.task_order.label }} {{ f.task_order.pdf.label }}
{{ f.task_order }} {{ f.task_order.pdf }}
{% for error in f.task_order.errors %} {% for error in f.task_order.pdf.errors %}
<span class="usa-input__message">{{error}}</span> <span class="usa-input__message">{{error}}</span>
{% endfor %} {% endfor %}
</div> </div>
</template> </template>
<template v-else> <template v-else>
<p>Uploaded {{ f.task_order.data }}.</p> <p>Uploaded {{ f.task_order.pdf.data }}.</p>
<div> <div>
<button v-on:click="forceShowTaskOrder($event)">Change</button> <button v-on:click="forceShowTaskOrder($event)">Change</button>
</div> </div>
@ -125,52 +125,52 @@
{% endif %} {% endif %}
{{ TextInput( {{ TextInput(
f.task_order_number, f.task_order.number,
placeholder="e.g.: 1234567899C0001", placeholder="e.g.: 1234567899C0001",
tooltip="A Contracting Officer will likely be the best source for this number.", tooltip="A Contracting Officer will likely be the best source for this number.",
validation="anything" validation="anything"
) }} ) }}
{{ TextInput(f.uii_ids, {{ TextInput(f.request.uii_ids,
paragraph=True, paragraph=True,
placeholder="examples: \nDI 0CVA5786950 \nUN1945326361234786950", placeholder="examples: \nDI 0CVA5786950 \nUN1945326361234786950",
tooltip="A Unique Item Identifer is a unique code that helps the Department of Defense track and report on where and how digital assets are stored. <br>Not all applications have an existing UII number assigned." tooltip="A Unique Item Identifer is a unique code that helps the Department of Defense track and report on where and how digital assets are stored. <br>Not all applications have an existing UII number assigned."
) }} ) }}
{{ TextInput(f.pe_id, {{ TextInput(f.request.pe_id,
placeholder="e.g.: 0105688F", placeholder="e.g.: 0105688F",
validation="peNumber" validation="peNumber"
) }} ) }}
{{ TextInput(f.treasury_code,placeholder="e.g.: 00123456",validation="treasuryCode") }} {{ TextInput(f.request.treasury_code,placeholder="e.g.: 00123456",validation="treasuryCode") }}
{{ TextInput(f.ba_code,placeholder="e.g.: 02A",validation="baCode") }} {{ TextInput(f.request.ba_code,placeholder="e.g.: 02A",validation="baCode") }}
<hr /> <hr />
<h3>Contracting Officer (KO) Information</h3> <h3>Contracting Officer (KO) Information</h3>
<div class='form-row'> <div class='form-row'>
<div class='form-col form-col--half '>{{ TextInput(f.fname_co) }}</div> <div class='form-col form-col--half '>{{ TextInput(f.request.fname_co) }}</div>
<div class='form-col form-col--half '>{{ TextInput(f.lname_co) }}</div> <div class='form-col form-col--half '>{{ TextInput(f.request.lname_co) }}</div>
</div> </div>
<div class='form-row'> <div class='form-row'>
<div class='form-col form-col--half'>{{ TextInput(f.email_co,validation='email', placeholder='e.g. jane@mail.mil') }}</div> <div class='form-col form-col--half'>{{ TextInput(f.request.email_co,validation='email', placeholder='e.g. jane@mail.mil') }}</div>
<div class='form-col form-col--half'>{{ TextInput(f.office_co,placeholder="e.g.: WHS") }}</div> <div class='form-col form-col--half'>{{ TextInput(f.request.office_co,placeholder="e.g.: WHS") }}</div>
</div> </div>
<hr /> <hr />
<h3>Contracting Officer Representative (COR) Information</h3> <h3>Contracting Officer Representative (COR) Information</h3>
<div class='form-row'> <div class='form-row'>
<div class='form-col form-col--half '>{{ TextInput(f.fname_cor) }}</div> <div class='form-col form-col--half '>{{ TextInput(f.request.fname_cor) }}</div>
<div class='form-col form-col--half '>{{ TextInput(f.lname_cor) }}</div> <div class='form-col form-col--half '>{{ TextInput(f.request.lname_cor) }}</div>
</div> </div>
<div class='form-row'> <div class='form-row'>
<div class='form-col form-col--half'>{{ TextInput(f.email_cor,validation='email', placeholder='e.g. jane@mail.mil') }}</div> <div class='form-col form-col--half'>{{ TextInput(f.request.email_cor,validation='email', placeholder='e.g. jane@mail.mil') }}</div>
<div class='form-col form-col--half'>{{ TextInput(f.office_cor,placeholder="e.g.: WHS") }}</div> <div class='form-col form-col--half'>{{ TextInput(f.request.office_cor,placeholder="e.g.: WHS") }}</div>
</div> </div>

View File

@ -1,6 +1,5 @@
import pytest import pytest
from atst.models.task_order import Source as TaskOrderSource
from atst.domain.exceptions import NotFoundError from atst.domain.exceptions import NotFoundError
from atst.domain.task_orders import TaskOrders from atst.domain.task_orders import TaskOrders
from atst.eda_client import MockEDAClient from atst.eda_client import MockEDAClient
@ -26,10 +25,3 @@ def test_nonexistent_task_order_raises_with_client(monkeypatch):
) )
with pytest.raises(NotFoundError): with pytest.raises(NotFoundError):
TaskOrders.get("some other fake numer") TaskOrders.get("some other fake numer")
def test_create_attachment(extended_financial_verification_data):
task_order_data = extended_financial_verification_data.copy()
task_order_data["pdf"] = task_order_data.pop("task_order")
task_order = TaskOrders.get_or_create_task_order("abc123", task_order_data)
assert task_order.pdf

View File

@ -1,92 +1,92 @@
import pytest # import pytest
from werkzeug.datastructures import ImmutableMultiDict # from werkzeug.datastructures import ImmutableMultiDict
from atst.forms.financial import FinancialForm, ExtendedFinancialForm # from atst.forms.financial import FinancialForm, ExtendedFinancialForm
from atst.domain.requests.financial_verification import PENumberValidator # from atst.domain.requests.financial_verification import PENumberValidator
@pytest.mark.parametrize( # @pytest.mark.parametrize(
"input_,expected", # "input_,expected",
[ # [
("0603502N", None), # ("0603502N", None),
("0603502NZ", None), # ("0603502NZ", None),
("603502N", "0603502N"), # ("603502N", "0603502N"),
("063502N", "0603502N"), # ("063502N", "0603502N"),
("63502N", "0603502N"), # ("63502N", "0603502N"),
], # ],
) # )
def test_suggest_pe_id(input_, expected): # def test_suggest_pe_id(input_, expected):
assert PENumberValidator().suggest_pe_id(input_) == expected # assert PENumberValidator().suggest_pe_id(input_) == expected
def test_funding_type_other_not_required_if_funding_type_is_not_other(): # def test_funding_type_other_not_required_if_funding_type_is_not_other():
form_data = {"funding_type": "PROC"} # form_data = {"funding_type": "PROC"}
form = ExtendedFinancialForm(data=form_data) # form = ExtendedFinancialForm(data=form_data)
form.validate() # form.validate()
assert "funding_type_other" not in form.errors # assert "funding_type_other" not in form.errors
def test_funding_type_other_required_if_funding_type_is_other(): # def test_funding_type_other_required_if_funding_type_is_other():
form_data = {"funding_type": "OTHER"} # form_data = {"funding_type": "OTHER"}
form = ExtendedFinancialForm(data=form_data) # form = ExtendedFinancialForm(data=form_data)
form.validate() # form.validate()
assert "funding_type_other" in form.errors # assert "funding_type_other" in form.errors
@pytest.mark.parametrize( # @pytest.mark.parametrize(
"input_,expected", # "input_,expected",
[ # [
("1234", True), # ("1234", True),
("123456", True), # ("123456", True),
("0001234", True), # ("0001234", True),
("000123456", True), # ("000123456", True),
("12345", False), # ("12345", False),
("00012345", False), # ("00012345", False),
("0001234567", False), # ("0001234567", False),
("000000", False), # ("000000", False),
], # ],
) # )
def test_treasury_code_validation(input_, expected): # def test_treasury_code_validation(input_, expected):
form_data = ImmutableMultiDict([("treasury_code", input_)]) # form_data = ImmutableMultiDict([("treasury_code", input_)])
form = FinancialForm(form_data) # form = FinancialForm(form_data)
form.validate() # form.validate()
is_valid = "treasury_code" not in form.errors # is_valid = "treasury_code" not in form.errors
assert is_valid == expected # assert is_valid == expected
@pytest.mark.parametrize( # @pytest.mark.parametrize(
"input_,expected", # "input_,expected",
[ # [
("1", False), # ("1", False),
("12", True), # ("12", True),
("01", True), # ("01", True),
("0A", False), # ("0A", False),
("A", False), # ("A", False),
("AB", False), # ("AB", False),
("123", True), # ("123", True),
("012", True), # ("012", True),
("12A", True), # ("12A", True),
("02A", True), # ("02A", True),
("0012", False), # ("0012", False),
("012A", False), # ("012A", False),
("2AB", False), # ("2AB", False),
], # ],
) # )
def test_ba_code_validation(input_, expected): # def test_ba_code_validation(input_, expected):
form_data = ImmutableMultiDict([("ba_code", input_)]) # form_data = ImmutableMultiDict([("ba_code", input_)])
form = FinancialForm(form_data) # form = FinancialForm(form_data)
form.validate() # form.validate()
is_valid = "ba_code" not in form.errors # is_valid = "ba_code" not in form.errors
assert is_valid == expected # assert is_valid == expected
def test_can_submit_zero_for_clin(): # def test_can_submit_zero_for_clin():
form_first = ExtendedFinancialForm() # form_first = ExtendedFinancialForm()
form_first.validate() # form_first.validate()
assert "clin_0001" in form_first.errors # assert "clin_0001" in form_first.errors
form_data = ImmutableMultiDict([("clin_0001", "0")]) # form_data = ImmutableMultiDict([("clin_0001", "0")])
form_second = ExtendedFinancialForm(form_data) # form_second = ExtendedFinancialForm(form_data)
form_second.validate() # form_second.validate()
assert "clin_0001" not in form_second.errors # assert "clin_0001" not in form_second.errors

View File

@ -1,6 +1,7 @@
import pytest import pytest
from unittest.mock import MagicMock from unittest.mock import MagicMock
from flask import url_for from flask import url_for
import datetime
from atst.eda_client import MockEDAClient from atst.eda_client import MockEDAClient
from atst.routes.requests.financial_verification import ( from atst.routes.requests.financial_verification import (
@ -28,19 +29,35 @@ from atst.utils import pick
@pytest.fixture @pytest.fixture
def fv_data(): def fv_data():
return { return {
"pe_id": "123", "request-pe_id": "123",
"task_order_number": MockEDAClient.MOCK_CONTRACT_NUMBER, "task_order-number": MockEDAClient.MOCK_CONTRACT_NUMBER,
"fname_co": "Contracting", "request-fname_co": "Contracting",
"lname_co": "Officer", "request-lname_co": "Officer",
"email_co": "jane@mail.mil", "request-email_co": "jane@mail.mil",
"office_co": "WHS", "request-office_co": "WHS",
"fname_cor": "Officer", "request-fname_cor": "Officer",
"lname_cor": "Representative", "request-lname_cor": "Representative",
"email_cor": "jane@mail.mil", "request-email_cor": "jane@mail.mil",
"office_cor": "WHS", "request-office_cor": "WHS",
"uii_ids": "1234", "request-uii_ids": "1234",
"treasury_code": "00123456", "request-treasury_code": "00123456",
"ba_code": "02A", "request-ba_code": "02A",
}
@pytest.fixture
def e_fv_data(pdf_upload):
return {
"task_order-funding_type": "RDTE",
"task_order-funding_type_other": "other",
"task_order-expiration_date": "1/1/{}".format(datetime.date.today().year + 1),
"task_order-clin_0001": "50000",
"task_order-clin_0003": "13000",
"task_order-clin_1001": "30000",
"task_order-clin_1003": "7000",
"task_order-clin_2001": "30000",
"task_order-clin_2003": "7000",
"task_order-pdf": pdf_upload,
} }
@ -81,7 +98,7 @@ def test_update_fv_re_enter_pe_number(fv_data):
def test_update_fv_invalid_task_order_number(fv_data): def test_update_fv_invalid_task_order_number(fv_data):
request = RequestFactory.create() request = RequestFactory.create()
user = UserFactory.create() user = UserFactory.create()
data = {**fv_data, "task_order_number": "DCA10096D0051"} data = {**fv_data, "task_order-number": "DCA10096D0051"}
update_fv = UpdateFinancialVerification( update_fv = UpdateFinancialVerification(
TrueValidator, TrueValidator,
TaskOrderNumberValidator(), TaskOrderNumberValidator(),
@ -95,10 +112,10 @@ def test_update_fv_invalid_task_order_number(fv_data):
update_fv.execute() update_fv.execute()
def test_update_fv_extended(fv_data, extended_financial_verification_data): def test_update_fv_extended(fv_data, e_fv_data):
request = RequestFactory.create() request = RequestFactory.create()
user = UserFactory.create() user = UserFactory.create()
data = {**fv_data, **extended_financial_verification_data} data = {**fv_data, **e_fv_data}
update_fv = UpdateFinancialVerification( update_fv = UpdateFinancialVerification(
TrueValidator, TaskOrderNumberValidator(), user, request, data, is_extended=True TrueValidator, TaskOrderNumberValidator(), user, request, data, is_extended=True
) )
@ -201,47 +218,41 @@ def test_save_draft_and_then_submit():
).execute() ).execute()
def test_updated_request_has_pdf(fv_data, extended_financial_verification_data): def test_updated_request_has_pdf(fv_data, e_fv_data):
request = RequestFactory.create() request = RequestFactory.create()
user = UserFactory.create() user = UserFactory.create()
data = { data = {**fv_data, **e_fv_data, "task_order-number": "DCA10096D0051"}
**fv_data,
**extended_financial_verification_data,
"task_order_number": "DCA10096D0051",
}
updated_request = UpdateFinancialVerification( updated_request = UpdateFinancialVerification(
TrueValidator, TrueValidator, user, request, data, is_extended=True TrueValidator, TrueValidator, user, request, data, is_extended=True
).execute() ).execute()
assert updated_request.task_order.pdf assert updated_request.task_order.pdf
def test_can_save_draft_with_just_pdf(extended_financial_verification_data): def test_can_save_draft_with_just_pdf(e_fv_data):
request = RequestFactory.create() request = RequestFactory.create()
user = UserFactory.create() user = UserFactory.create()
data = {"task_order": extended_financial_verification_data["task_order"]} data = {"task_order-pdf": e_fv_data["task_order-pdf"]}
SaveFinancialVerificationDraft( SaveFinancialVerificationDraft(
TrueValidator, TrueValidator, user, request, data, is_extended=True TrueValidator, TrueValidator, user, request, data, is_extended=True
).execute() ).execute()
form = GetFinancialVerificationForm(user, request, is_extended=True).execute() form = GetFinancialVerificationForm(user, request, is_extended=True).execute()
assert form.task_order assert form.task_order.pdf
def test_task_order_info_present_in_extended_form( def test_task_order_info_present_in_extended_form(fv_data, e_fv_data):
fv_data, extended_financial_verification_data
):
request = RequestFactory.create() request = RequestFactory.create()
user = UserFactory.create() user = UserFactory.create()
data = { data = {
"clin_0001": extended_financial_verification_data["clin_0001"], "task_order-clin_0001": "1",
"task_order_number": fv_data["task_order_number"], "task_order-number": fv_data["task_order-number"],
} }
SaveFinancialVerificationDraft( SaveFinancialVerificationDraft(
TrueValidator, TrueValidator, user, request, data, is_extended=True TrueValidator, TrueValidator, user, request, data, is_extended=True
).execute() ).execute()
form = GetFinancialVerificationForm(user, request, is_extended=True).execute() form = GetFinancialVerificationForm(user, request, is_extended=True).execute()
assert form.clin_0001.data assert form.task_order.clin_0001.data
def test_simple_form_does_not_generate_task_order(fv_data): def test_simple_form_does_not_generate_task_order(fv_data):
@ -255,22 +266,17 @@ def test_simple_form_does_not_generate_task_order(fv_data):
assert updated_request.task_order is None assert updated_request.task_order is None
def test_can_save_draft_with_funding_type( def test_can_save_draft_with_funding_type(fv_data, e_fv_data):
fv_data, extended_financial_verification_data
):
request = RequestFactory.create() request = RequestFactory.create()
user = UserFactory.create() user = UserFactory.create()
data = { data = {
"task_order_number": fv_data["task_order_number"], "task_order-number": fv_data["task_order-number"],
"funding_type": extended_financial_verification_data["funding_type"], "task_order-funding_type": e_fv_data["task_order-funding_type"],
} }
updated_request = SaveFinancialVerificationDraft( updated_request = SaveFinancialVerificationDraft(
TrueValidator, TrueValidator, user, request, data, is_extended=False TrueValidator, TrueValidator, user, request, data, is_extended=False
).execute() ).execute()
import ipdb
ipdb.set_trace()
assert updated_request.task_order.funding_type assert updated_request.task_order.funding_type
@ -317,7 +323,7 @@ def test_manual_task_order_triggers_extended_form(client, user_session, fv_data)
user = UserFactory.create() user = UserFactory.create()
request = RequestFactory.create(creator=user) request = RequestFactory.create(creator=user)
data = {**fv_data, "task_order_number": "DCA10096D0053"} data = {**fv_data, "task_order-number": "DCA10096D0053"}
UpdateFinancialVerification( UpdateFinancialVerification(
TrueValidator, TrueValidator, user, request, data, is_extended=False TrueValidator, TrueValidator, user, request, data, is_extended=False