Merge pull request #560 from dod-ccpo/ko-dod-id-toggle

Toggle DOD ID Input For Officers
This commit is contained in:
montana-mil 2019-01-21 14:03:45 -05:00 committed by GitHub
commit 4afafe7217
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 70 deletions

View File

@ -10,9 +10,9 @@ from wtforms.fields import (
) )
from wtforms.fields.html5 import DateField, TelField from wtforms.fields.html5 import DateField, TelField
from wtforms.widgets import ListWidget, CheckboxInput from wtforms.widgets import ListWidget, CheckboxInput
from wtforms.validators import Required, Length from wtforms.validators import Length
from atst.forms.validators import IsNumber, PhoneNumber, RequiredIfNot from atst.forms.validators import IsNumber, PhoneNumber, RequiredIf
from .forms import CacheableForm from .forms import CacheableForm
from .data import ( from .data import (
@ -117,7 +117,11 @@ class OversightForm(CacheableForm):
) )
ko_dod_id = StringField( ko_dod_id = StringField(
translate("forms.task_order.oversight_dod_id_label"), translate("forms.task_order.oversight_dod_id_label"),
validators=[Required(), Length(min=10), IsNumber()], validators=[
RequiredIf(lambda form: form._fields.get("ko_invite").data),
Length(min=10),
IsNumber(),
],
) )
am_cor = BooleanField(translate("forms.task_order.oversight_am_cor_label")) am_cor = BooleanField(translate("forms.task_order.oversight_am_cor_label"))
@ -128,11 +132,21 @@ class OversightForm(CacheableForm):
cor_email = StringField(translate("forms.task_order.oversight_email_label")) cor_email = StringField(translate("forms.task_order.oversight_email_label"))
cor_phone_number = TelField( cor_phone_number = TelField(
translate("forms.task_order.oversight_phone_label"), translate("forms.task_order.oversight_phone_label"),
validators=[RequiredIfNot("am_cor"), PhoneNumber()], validators=[
RequiredIf(lambda form: not form._fields.get("am_cor").data),
PhoneNumber(),
],
) )
cor_dod_id = StringField( cor_dod_id = StringField(
translate("forms.task_order.oversight_dod_id_label"), translate("forms.task_order.oversight_dod_id_label"),
validators=[RequiredIfNot("am_cor"), Length(min=10), IsNumber()], validators=[
RequiredIf(
lambda form: not form._fields.get("am_cor").data
and form._fields.get("cor_invite").data
),
Length(min=10),
IsNumber(),
],
) )
so_first_name = StringField( so_first_name = StringField(
@ -145,7 +159,11 @@ class OversightForm(CacheableForm):
) )
so_dod_id = StringField( so_dod_id = StringField(
translate("forms.task_order.oversight_dod_id_label"), translate("forms.task_order.oversight_dod_id_label"),
validators=[Required(), Length(min=10), IsNumber()], validators=[
RequiredIf(lambda form: form._fields.get("so_invite").data),
Length(min=10),
IsNumber(),
],
) )
ko_invite = BooleanField( ko_invite = BooleanField(

View File

@ -80,26 +80,22 @@ def ListItemsUnique(message=translate("forms.validators.list_items_unique_messag
return _list_items_unique return _list_items_unique
def RequiredIfNot(other_field_name, message=translate("forms.validators.is_required")): def RequiredIf(criteria_function, message=translate("forms.validators.is_required")):
""" A validator which makes a field required only if another field """ A validator which makes a field required only if another field
has a falsy value has a truthy value
Args: Args:
other_field_name (str): the name of the field we check before criteria_function (function): calling this function on form results
determining if this field is required; if this other field is falsy, in a boolean value that we want to check against;
the field will be required if it's True, we require the field
message (str): an optional message to display if the field is message (str): an optional message to display if the field is
required but hasNone value required but hasNone value
""" """
def _required_if_not(form, field): def _required_if(form, field):
other_field = form._fields.get(other_field_name) if criteria_function(form):
if other_field is None:
raise Exception('no field named "%s" in form' % self.other_field_name)
if not bool(other_field.data):
if field.data is None: if field.data is None:
raise ValidationError(message) raise ValidationError(message)
else: else:
raise StopValidation() raise StopValidation()
return _required_if_not return _required_if

View File

@ -81,6 +81,12 @@ class ShowTaskOrderWorkflow:
elif self._section["section"] == "oversight": elif self._section["section"] == "oversight":
if self.user.dod_id == self.task_order.cor_dod_id: if self.user.dod_id == self.task_order.cor_dod_id:
self._form.am_cor.data = True self._form.am_cor.data = True
if self.task_order.contracting_officer:
self._form.ko_invite.data = True
if self.task_order.contracting_officer_representative:
self._form.cor_invite.data = True
if self.task_order.security_officer:
self._form.so_invite.data = True
else: else:
self._form = self._section[form_type]() self._form = self._section[form_type]()

View File

@ -3,7 +3,7 @@ import textinput from '../text_input'
import checkboxinput from '../checkbox_input' import checkboxinput from '../checkbox_input'
export default { export default {
name: 'cor', name: 'oversight',
mixins: [FormMixin], mixins: [FormMixin],
@ -21,11 +21,17 @@ export default {
data: function () { data: function () {
const { const {
am_cor = false am_cor = false,
ko_invite = false,
cor_invite = false,
so_invite = false,
} = this.initialData } = this.initialData
return { return {
am_cor am_cor,
ko_invite,
cor_invite,
so_invite,
} }
} }
} }

View File

@ -11,7 +11,7 @@ import textinput from './components/text_input'
import checkboxinput from './components/checkbox_input' import checkboxinput from './components/checkbox_input'
import DetailsOfUse from './components/forms/details_of_use' import DetailsOfUse from './components/forms/details_of_use'
import poc from './components/forms/poc' import poc from './components/forms/poc'
import cor from './components/forms/cor' import oversight from './components/forms/oversight'
import financial from './components/forms/financial' import financial from './components/forms/financial'
import toggler from './components/toggler' import toggler from './components/toggler'
import NewApplication from './components/forms/new_application' import NewApplication from './components/forms/new_application'
@ -45,7 +45,7 @@ const app = new Vue({
checkboxinput, checkboxinput,
DetailsOfUse, DetailsOfUse,
poc, poc,
cor, oversight,
financial, financial,
NewApplication, NewApplication,
selector, selector,

View File

@ -13,31 +13,37 @@
<!-- Oversight Section --> <!-- Oversight Section -->
<h3 class="subheading">{{ "task_orders.new.oversight.ko_info_title" | translate }}</h3> <h3 class="subheading">{{ "task_orders.new.oversight.ko_info_title" | translate }}</h3>
<p>{{ "task_orders.new.oversight.ko_info_paragraph" | translate }}</p> <p>{{ "task_orders.new.oversight.ko_info_paragraph" | translate }}</p>
{{ UserInfo(form.ko_first_name, form.ko_last_name, form.ko_email, form.ko_phone_number) }} <oversight inline-template v-bind:initial-data='{{ form.data|tojson }}'>
{{ CheckboxInput(form.ko_invite) }}
{{ TextInput(form.ko_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
<hr />
<h3 class="subheading">{{ "task_orders.new.oversight.cor_info_title" | translate }}</h3>
<p>{{ "task_orders.new.oversight.cor_info_paragraph" | translate }}</p>
<cor inline-template v-bind:initial-data='{{ form.data|tojson }}'>
<div class='usa-input'> <div class='usa-input'>
{{ UserInfo(form.ko_first_name, form.ko_last_name, form.ko_email, form.ko_phone_number) }}
{{ CheckboxInput(form.ko_invite) }}
<template v-if="ko_invite">
{{ TextInput(form.ko_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
</template>
<hr />
<h3 class="subheading">{{ "task_orders.new.oversight.cor_info_title" | translate }}</h3>
<p>{{ "task_orders.new.oversight.cor_info_paragraph" | translate }}</p>
{{ CheckboxInput(form.am_cor) }} {{ CheckboxInput(form.am_cor) }}
<template v-if="!am_cor"> <template v-if="!am_cor">
{{ UserInfo(form.cor_first_name, form.cor_last_name, form.cor_email, form.cor_phone_number) }} {{ UserInfo(form.cor_first_name, form.cor_last_name, form.cor_email, form.cor_phone_number) }}
{{ CheckboxInput(form.cor_invite) }} {{ CheckboxInput(form.cor_invite) }}
{{ TextInput(form.cor_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}} <template v-if="cor_invite">
{{ TextInput(form.cor_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
</template>
</template>
<hr />
<h3 class="subheading">{{ "task_orders.new.oversight.so_info_title" | translate }}</h3>
<p>{{ "task_orders.new.oversight.so_info_paragraph" | translate }}</p>
{{ UserInfo(form.so_first_name, form.so_last_name, form.so_email, form.so_phone_number) }}
{{ CheckboxInput(form.so_invite) }}
<template v-if="so_invite">
{{ TextInput(form.so_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
</template> </template>
</div> </div>
</cor> </oversight>
<hr />
<h3 class="subheading">{{ "task_orders.new.oversight.so_info_title" | translate }}</h3>
<p>{{ "task_orders.new.oversight.so_info_paragraph" | translate }}</p>
{{ UserInfo(form.so_first_name, form.so_last_name, form.so_email, form.so_phone_number) }}
{{ CheckboxInput(form.so_invite) }}
{{ TextInput(form.so_dod_id, placeholder="1234567890", tooltip="Why", tooltip_title='Why', validation='dodId')}}
{% endblock %} {% endblock %}

View File

@ -103,15 +103,6 @@ def dummy_form():
return DummyForm() return DummyForm()
@pytest.fixture
def dummy_form_with_field():
def set_field(name, value):
data = DummyField(data=value, name=name)
return DummyForm(data=OrderedDict({name: data}))
return set_field
@pytest.fixture @pytest.fixture
def dummy_field(): def dummy_field():
return DummyField() return DummyField()

View File

@ -6,7 +6,7 @@ from atst.forms.validators import (
IsNumber, IsNumber,
PhoneNumber, PhoneNumber,
ListItemsUnique, ListItemsUnique,
RequiredIfNot, RequiredIf,
) )
@ -81,30 +81,19 @@ class TestListItemsUnique:
validator(dummy_form, dummy_field) validator(dummy_form, dummy_field)
class TestRequiredIfNot: class TestRequiredIf:
def test_RequiredIfNot_requires_field_if_arg_is_falsy( def test_RequiredIf_requires_field_if_arg_is_truthy(self, dummy_form, dummy_field):
self, dummy_form_with_field, dummy_field validator = RequiredIf(lambda form: True)
):
form = dummy_form_with_field("arg", False)
validator = RequiredIfNot("arg")
dummy_field.data = None dummy_field.data = None
with pytest.raises(ValidationError): with pytest.raises(ValidationError):
validator(form, dummy_field) validator(dummy_form, dummy_field)
def test_RequiredIfNot_does_not_require_field_if_arg_is_truthy( def test_RequiredIf_does_not_require_field_if_arg_is_falsy(
self, dummy_form_with_field, dummy_field self, dummy_form, dummy_field
): ):
form = dummy_form_with_field("arg", True) validator = RequiredIf(lambda form: False)
validator = RequiredIfNot("arg")
dummy_field.data = None dummy_field.data = None
with pytest.raises(StopValidation): with pytest.raises(StopValidation):
validator(form, dummy_field)
def test_RequiredIfNot_arg_is_None_raises_error(self, dummy_form, dummy_field):
validator = RequiredIfNot("arg")
dummy_field.data = "some data"
with pytest.raises(Exception):
validator(dummy_form, dummy_field) validator(dummy_form, dummy_field)