Merge pull request #585 from dod-ccpo/save-draft-without-button

Save as draft without draft button
This commit is contained in:
George Drummond 2019-02-01 14:35:53 -05:00 committed by GitHub
commit 6ce7981a06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 80 additions and 50 deletions

View File

@ -1,5 +1,4 @@
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
from flask import current_app as app from flask import current_app as app
from atst.database import db from atst.database import db
@ -17,6 +16,7 @@ class TaskOrderError(Exception):
class TaskOrders(object): class TaskOrders(object):
SECTIONS = { SECTIONS = {
"app_info": [ "app_info": [
"portfolio_name",
"scope", "scope",
"defense_component", "defense_component",
"app_migration", "app_migration",
@ -93,27 +93,37 @@ class TaskOrders(object):
return task_order return task_order
@classmethod @classmethod
def is_section_complete(cls, task_order, section): def section_completion_status(cls, task_order, section):
if section in TaskOrders.sections(): if section in TaskOrders.mission_owner_sections():
passed = []
failed = []
for attr in TaskOrders.SECTIONS[section]: for attr in TaskOrders.SECTIONS[section]:
if getattr(task_order, attr) is None: if getattr(task_order, attr):
return False passed.append(attr)
else:
failed.append(attr)
return True if not failed:
return "complete"
elif passed and failed:
return "draft"
else: return "incomplete"
return False
@classmethod @classmethod
def all_sections_complete(cls, task_order): def all_sections_complete(cls, task_order):
for section in TaskOrders.SECTIONS.keys(): for section in TaskOrders.SECTIONS.keys():
if not TaskOrders.is_section_complete(task_order, section): if (
TaskOrders.section_completion_status(task_order, section)
is not "complete"
):
return False return False
return True return True
@classmethod @classmethod
def sections(cls): def mission_owner_sections(cls):
section_list = TaskOrders.SECTIONS section_list = TaskOrders.SECTIONS
if not app.config.get("CLASSIFIED"): if not app.config.get("CLASSIFIED"):
section_list["funding"] = TaskOrders.UNCLASSIFIED_FUNDING section_list["funding"] = TaskOrders.UNCLASSIFIED_FUNDING

View File

@ -10,7 +10,7 @@ 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 Length, InputRequired from wtforms.validators import Length, Required, Optional
from flask_wtf.file import FileAllowed from flask_wtf.file import FileAllowed
from atst.forms.validators import IsNumber, PhoneNumber, RequiredIf from atst.forms.validators import IsNumber, PhoneNumber, RequiredIf
@ -31,6 +31,7 @@ class AppInfoForm(CacheableForm):
portfolio_name = StringField( portfolio_name = StringField(
translate("forms.task_order.portfolio_name_label"), translate("forms.task_order.portfolio_name_label"),
description=translate("forms.task_order.portfolio_name_description"), description=translate("forms.task_order.portfolio_name_description"),
validators=[Required()],
) )
scope = TextAreaField( scope = TextAreaField(
translate("forms.task_order.scope_label"), translate("forms.task_order.scope_label"),
@ -44,11 +45,14 @@ class AppInfoForm(CacheableForm):
description=translate("forms.task_order.app_migration.description"), description=translate("forms.task_order.app_migration.description"),
choices=APP_MIGRATION, choices=APP_MIGRATION,
default="", default="",
validators=[Optional()],
) )
native_apps = RadioField( native_apps = RadioField(
translate("forms.task_order.native_apps.label"), translate("forms.task_order.native_apps.label"),
description=translate("forms.task_order.native_apps.description"), description=translate("forms.task_order.native_apps.description"),
choices=[("yes", "Yes"), ("no", "No"), ("not_sure", "Not Sure")], choices=[("yes", "Yes"), ("no", "No"), ("not_sure", "Not Sure")],
default="",
validators=[Optional()],
) )
complexity = SelectMultipleField( complexity = SelectMultipleField(
translate("forms.task_order.complexity.label"), translate("forms.task_order.complexity.label"),
@ -73,6 +77,7 @@ class AppInfoForm(CacheableForm):
description=translate("forms.task_order.team_experience.description"), description=translate("forms.task_order.team_experience.description"),
choices=TEAM_EXPERIENCE, choices=TEAM_EXPERIENCE,
default="", default="",
validators=[Optional()],
) )
@ -98,28 +103,16 @@ class FundingForm(CacheableForm):
render_kw={"accept": ".pdf,.png,application/pdf,image/png"}, render_kw={"accept": ".pdf,.png,application/pdf,image/png"},
) )
clin_01 = DecimalField( clin_01 = DecimalField(
translate("forms.task_order.clin_01_label"), translate("forms.task_order.clin_01_label"), validators=[Optional()]
validators=[
InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
) )
clin_02 = DecimalField( clin_02 = DecimalField(
translate("forms.task_order.clin_02_label"), translate("forms.task_order.clin_02_label"), validators=[Optional()]
validators=[
InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
) )
clin_03 = DecimalField( clin_03 = DecimalField(
translate("forms.task_order.clin_03_label"), translate("forms.task_order.clin_03_label"), validators=[Optional()]
validators=[
InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
) )
clin_04 = DecimalField( clin_04 = DecimalField(
translate("forms.task_order.clin_04_label"), translate("forms.task_order.clin_04_label"), validators=[Optional()]
validators=[
InputRequired(message=(translate("forms.task_order.clin_validation_error")))
],
) )
@ -141,7 +134,8 @@ class OversightForm(CacheableForm):
ko_last_name = StringField(translate("forms.task_order.oversight_last_name_label")) ko_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
ko_email = StringField(translate("forms.task_order.oversight_email_label")) ko_email = StringField(translate("forms.task_order.oversight_email_label"))
ko_phone_number = TelField( ko_phone_number = TelField(
translate("forms.task_order.oversight_phone_label"), validators=[PhoneNumber()] translate("forms.task_order.oversight_phone_label"),
validators=[Optional(), PhoneNumber()],
) )
ko_dod_id = StringField( ko_dod_id = StringField(
translate("forms.task_order.oversight_dod_id_label"), translate("forms.task_order.oversight_dod_id_label"),
@ -162,6 +156,7 @@ class OversightForm(CacheableForm):
translate("forms.task_order.oversight_phone_label"), translate("forms.task_order.oversight_phone_label"),
validators=[ validators=[
RequiredIf(lambda form: not form._fields.get("am_cor").data), RequiredIf(lambda form: not form._fields.get("am_cor").data),
Optional(),
PhoneNumber(), PhoneNumber(),
], ],
) )
@ -183,7 +178,8 @@ class OversightForm(CacheableForm):
so_last_name = StringField(translate("forms.task_order.oversight_last_name_label")) so_last_name = StringField(translate("forms.task_order.oversight_last_name_label"))
so_email = StringField(translate("forms.task_order.oversight_email_label")) so_email = StringField(translate("forms.task_order.oversight_email_label"))
so_phone_number = TelField( so_phone_number = TelField(
translate("forms.task_order.oversight_phone_label"), validators=[PhoneNumber()] translate("forms.task_order.oversight_phone_label"),
validators=[Optional(), PhoneNumber()],
) )
so_dod_id = StringField( so_dod_id = StringField(
translate("forms.task_order.oversight_dod_id_label"), translate("forms.task_order.oversight_dod_id_label"),

View File

@ -103,8 +103,9 @@ class ShowTaskOrderWorkflow:
if self.task_order: if self.task_order:
for section in screen_info: for section in screen_info:
if TaskOrders.is_section_complete(self.task_order, section["section"]): section["completion"] = TaskOrders.section_completion_status(
section["complete"] = True self.task_order, section["section"]
)
return screen_info return screen_info

View File

@ -107,6 +107,13 @@
padding: 1px 2px; padding: 1px 2px;
} }
&--draft:before {
background: $color-gold;
border: none;
font-size: $h6-font-size;
mask-image: url('#{$asset-path}/icons/alert.svg');
}
&--incomplete:before { &--incomplete:before {
border: 2px solid $color-gray-light; border: 2px solid $color-gray-light;
} }

View File

@ -40,7 +40,6 @@
<div class='action-group'> <div class='action-group'>
<input type='submit' class='usa-button usa-button-primary' value='Save & Continue' /> <input type='submit' class='usa-button usa-button-primary' value='Save & Continue' />
<input class='usa-button usa-button-secondary' value='Save Draft' />
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,15 +1,7 @@
<div class="progress-menu progress-menu--four"> <div class="progress-menu progress-menu--four">
<ul> <ul>
{% for s in screens %} {% for s in screens %}
{% if s.complete %} <li class="progress-menu__item progress-menu__item--{{ s.completion }}">
{% set step_indicator = 'complete' %}
{% elif loop.index == current %}
{% set step_indicator = 'active' %}
{% else %}
{% set step_indicator = 'incomplete' %}
{% endif %}
<li class="progress-menu__item progress-menu__item--{{ step_indicator }}">
<a <a
{% set class='' %} {% set class='' %}
{% if task_order_id %} {% if task_order_id %}

View File

@ -67,8 +67,23 @@
<h3 class="subheading">{{ "task_orders.new.review.reporting"| translate }} {{ TOEditLink(screen=1, anchor="reporting") }}</h3> <h3 class="subheading">{{ "task_orders.new.review.reporting"| translate }} {{ TOEditLink(screen=1, anchor="reporting") }}</h3>
<div class="row"> <div class="row">
{{ ReviewField(("forms.task_order.app_migration.label" | translate), ("forms.task_order.app_migration.{}".format(task_order.app_migration) | translate), filter="removeHtml") }} {{
{{ ReviewField(("forms.task_order.native_apps.label" | translate), ("forms.task_order.native_apps.{}".format(task_order.native_apps))| translate) }} ReviewField(
("forms.task_order.app_migration.label" | translate),
(
("forms.task_order.app_migration.{}".format(task_order.app_migration) | translate) if task_order.app_migration
)
)
}}
{{
ReviewField(
("forms.task_order.native_apps.label" | translate),
(
("forms.task_order.native_apps.{}".format(task_order.native_apps) | translate) if task_order.native_apps
)
)
}}
</div> </div>
<h4 class='task-order-form__heading'>{{ "task_orders.new.review.complexity"| translate }}</h4> <h4 class='task-order-form__heading'>{{ "task_orders.new.review.complexity"| translate }}</h4>
@ -104,7 +119,14 @@
{% endif %} {% endif %}
</div> </div>
{{ ReviewField(("forms.task_order.team_experience.label" |translate), ("forms.task_order.team_experience.{}".format(task_order.team_experience)) | translate) }} {{
ReviewField(
("forms.task_order.team_experience.label" |translate),
(
("forms.task_order.team_experience.{}".format(task_order.team_experience) | translate) if task_order.team_experience
)
)
}}
</div> </div>
<hr> <hr>

View File

@ -12,17 +12,21 @@ from tests.factories import (
) )
def test_is_section_complete(): def test_section_completion_status():
dict_keys = [k for k in TaskOrders.SECTIONS.keys()] dict_keys = [k for k in TaskOrders.SECTIONS.keys()]
section = dict_keys[0] section = dict_keys[0]
attrs = TaskOrders.SECTIONS[section].copy() attrs = TaskOrders.SECTIONS[section].copy()
attrs.remove("portfolio_name")
task_order = TaskOrderFactory.create(**{k: None for k in attrs}) task_order = TaskOrderFactory.create(**{k: None for k in attrs})
leftover = attrs.pop() leftover = attrs.pop()
for attr in attrs: for attr in attrs:
setattr(task_order, attr, "str12345") setattr(task_order, attr, "str12345")
assert not TaskOrders.is_section_complete(task_order, section)
assert TaskOrders.section_completion_status(task_order, section) == "draft"
setattr(task_order, leftover, "str12345") setattr(task_order, leftover, "str12345")
assert TaskOrders.is_section_complete(task_order, section) assert TaskOrders.section_completion_status(task_order, section) == "complete"
def test_all_sections_complete(): def test_all_sections_complete():

View File

@ -170,9 +170,9 @@ def test_show_task_order_display_screen(task_order):
screens = workflow.display_screens screens = workflow.display_screens
# every form section is complete # every form section is complete
for i in range(2): for i in range(2):
assert screens[i]["complete"] assert screens[i]["completion"] == "complete"
# the review section is not # the review section is not
assert not screens[3].get("complete") assert screens[3]["completion"] == "incomplete"
def test_update_task_order_with_no_task_order(): def test_update_task_order_with_no_task_order():

View File

@ -222,7 +222,6 @@ forms:
clin_02_label: 'CLIN 02: Classified' clin_02_label: 'CLIN 02: Classified'
clin_03_label: 'CLIN 03: Unclassified' clin_03_label: 'CLIN 03: Unclassified'
clin_04_label: 'CLIN 04: Classified' clin_04_label: 'CLIN 04: Classified'
clin_validation_error: Please enter a dollar amount
unclassified_clin_02_label: 'CLIN 02: Classified (available soon)' unclassified_clin_02_label: 'CLIN 02: Classified (available soon)'
unclassified_clin_04_label: 'CLIN 04: Classified (available soon)' unclassified_clin_04_label: 'CLIN 04: Classified (available soon)'
oversight_first_name_label: First Name oversight_first_name_label: First Name