Merge pull request #585 from dod-ccpo/save-draft-without-button
Save as draft without draft button
This commit is contained in:
commit
6ce7981a06
@ -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
|
||||||
|
@ -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"),
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 %}
|
||||||
|
@ -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 %}
|
||||||
|
@ -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>
|
||||||
|
@ -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():
|
||||||
|
@ -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():
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user