diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py index 235351a0..d54cd249 100644 --- a/atst/domain/task_orders.py +++ b/atst/domain/task_orders.py @@ -1,5 +1,4 @@ from sqlalchemy.orm.exc import NoResultFound - from flask import current_app as app from atst.database import db @@ -17,6 +16,7 @@ class TaskOrderError(Exception): class TaskOrders(object): SECTIONS = { "app_info": [ + "portfolio_name", "scope", "defense_component", "app_migration", @@ -93,27 +93,37 @@ class TaskOrders(object): return task_order @classmethod - def is_section_complete(cls, task_order, section): - if section in TaskOrders.sections(): + def section_completion_status(cls, task_order, section): + if section in TaskOrders.mission_owner_sections(): + passed = [] + failed = [] + for attr in TaskOrders.SECTIONS[section]: - if getattr(task_order, attr) is None: - return False + if getattr(task_order, attr): + passed.append(attr) + else: + failed.append(attr) - return True + if not failed: + return "complete" + elif passed and failed: + return "draft" - else: - return False + return "incomplete" @classmethod def all_sections_complete(cls, task_order): 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 True @classmethod - def sections(cls): + def mission_owner_sections(cls): section_list = TaskOrders.SECTIONS if not app.config.get("CLASSIFIED"): section_list["funding"] = TaskOrders.UNCLASSIFIED_FUNDING diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index 2075e834..9a536db1 100644 --- a/atst/forms/task_order.py +++ b/atst/forms/task_order.py @@ -10,7 +10,7 @@ from wtforms.fields import ( ) from wtforms.fields.html5 import DateField, TelField 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 atst.forms.validators import IsNumber, PhoneNumber, RequiredIf @@ -31,6 +31,7 @@ class AppInfoForm(CacheableForm): portfolio_name = StringField( translate("forms.task_order.portfolio_name_label"), description=translate("forms.task_order.portfolio_name_description"), + validators=[Required()], ) scope = TextAreaField( translate("forms.task_order.scope_label"), @@ -44,11 +45,14 @@ class AppInfoForm(CacheableForm): description=translate("forms.task_order.app_migration.description"), choices=APP_MIGRATION, default="", + validators=[Optional()], ) native_apps = RadioField( translate("forms.task_order.native_apps.label"), description=translate("forms.task_order.native_apps.description"), choices=[("yes", "Yes"), ("no", "No"), ("not_sure", "Not Sure")], + default="", + validators=[Optional()], ) complexity = SelectMultipleField( translate("forms.task_order.complexity.label"), @@ -73,6 +77,7 @@ class AppInfoForm(CacheableForm): description=translate("forms.task_order.team_experience.description"), choices=TEAM_EXPERIENCE, default="", + validators=[Optional()], ) @@ -98,28 +103,16 @@ class FundingForm(CacheableForm): render_kw={"accept": ".pdf,.png,application/pdf,image/png"}, ) clin_01 = DecimalField( - translate("forms.task_order.clin_01_label"), - validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) - ], + translate("forms.task_order.clin_01_label"), validators=[Optional()] ) clin_02 = DecimalField( - translate("forms.task_order.clin_02_label"), - validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) - ], + translate("forms.task_order.clin_02_label"), validators=[Optional()] ) clin_03 = DecimalField( - translate("forms.task_order.clin_03_label"), - validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) - ], + translate("forms.task_order.clin_03_label"), validators=[Optional()] ) clin_04 = DecimalField( - translate("forms.task_order.clin_04_label"), - validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) - ], + translate("forms.task_order.clin_04_label"), validators=[Optional()] ) @@ -141,7 +134,8 @@ class OversightForm(CacheableForm): ko_last_name = StringField(translate("forms.task_order.oversight_last_name_label")) ko_email = StringField(translate("forms.task_order.oversight_email_label")) 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( translate("forms.task_order.oversight_dod_id_label"), @@ -162,6 +156,7 @@ class OversightForm(CacheableForm): translate("forms.task_order.oversight_phone_label"), validators=[ RequiredIf(lambda form: not form._fields.get("am_cor").data), + Optional(), PhoneNumber(), ], ) @@ -183,7 +178,8 @@ class OversightForm(CacheableForm): so_last_name = StringField(translate("forms.task_order.oversight_last_name_label")) so_email = StringField(translate("forms.task_order.oversight_email_label")) 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( translate("forms.task_order.oversight_dod_id_label"), diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index 3a860311..c8ff4e14 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -103,8 +103,9 @@ class ShowTaskOrderWorkflow: if self.task_order: for section in screen_info: - if TaskOrders.is_section_complete(self.task_order, section["section"]): - section["complete"] = True + section["completion"] = TaskOrders.section_completion_status( + self.task_order, section["section"] + ) return screen_info diff --git a/styles/components/_progress_menu.scss b/styles/components/_progress_menu.scss index 01e2de26..0da6d34e 100644 --- a/styles/components/_progress_menu.scss +++ b/styles/components/_progress_menu.scss @@ -107,6 +107,13 @@ 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 { border: 2px solid $color-gray-light; } diff --git a/templates/task_orders/_new.html b/templates/task_orders/_new.html index b80bced9..37f1ce74 100644 --- a/templates/task_orders/_new.html +++ b/templates/task_orders/_new.html @@ -40,7 +40,6 @@