From caddfb5ff082b3bed19f45f4ddd7b2cc99c5bb93 Mon Sep 17 00:00:00 2001 From: George Drummond Date: Mon, 28 Jan 2019 11:34:49 -0500 Subject: [PATCH 01/10] Save as draft without draft button --- atst/domain/task_orders.py | 31 +++++++++++++------ atst/forms/task_order.py | 30 +++++++++++++----- atst/routes/task_orders/new.py | 5 +-- styles/components/_progress_menu.scss | 7 +++++ templates/task_orders/_new.html | 1 - templates/task_orders/new/menu.html | 10 +----- tests/domain/test_task_orders.py | 9 ++++-- .../routes/task_orders/test_new_task_order.py | 4 +-- 8 files changed, 63 insertions(+), 34 deletions(-) diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py index 235351a0..fced1a3b 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 @@ -93,21 +92,33 @@ 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.SECTIONS: + passed = [] + failed = [] + for attr in TaskOrders.SECTIONS[section]: - if getattr(task_order, attr) is None: - return False + if not app.config.get("CLASSIFIED") and attr in ["clin_02", "clin_04"]: + pass + elif not getattr(task_order, attr): + failed.append(attr) + else: + passed.append(attr) - return True - - else: - return False + if not failed: + return "complete" + elif passed and failed: + return "draft" + else: + 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 diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index 2075e834..516e8ce8 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, InputRequired, 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"), @@ -100,25 +101,37 @@ class FundingForm(CacheableForm): clin_01 = DecimalField( translate("forms.task_order.clin_01_label"), validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) + Optional(), + InputRequired( + message=(translate("forms.task_order.clin_validation_error")) + ), ], ) clin_02 = DecimalField( translate("forms.task_order.clin_02_label"), validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) + Optional(), + InputRequired( + message=(translate("forms.task_order.clin_validation_error")) + ), ], ) clin_03 = DecimalField( translate("forms.task_order.clin_03_label"), validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) + Optional(), + InputRequired( + message=(translate("forms.task_order.clin_validation_error")) + ), ], ) clin_04 = DecimalField( translate("forms.task_order.clin_04_label"), validators=[ - InputRequired(message=(translate("forms.task_order.clin_validation_error"))) + Optional(), + InputRequired( + message=(translate("forms.task_order.clin_validation_error")) + ), ], ) @@ -141,7 +154,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 +176,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 +198,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 @@
-
{% endblock %} diff --git a/templates/task_orders/new/menu.html b/templates/task_orders/new/menu.html index c6620a83..296c44fd 100644 --- a/templates/task_orders/new/menu.html +++ b/templates/task_orders/new/menu.html @@ -1,15 +1,7 @@
- {{ ReviewField(("forms.task_order.team_experience.label" |translate), ("forms.task_order.team_experience.{}".format(task_order.team_experience)) | translate) }} + {% if task_order.team_experience %} + {{ ReviewField(("forms.task_order.team_experience.label" |translate), ("forms.task_order.team_experience.{}".format(task_order.team_experience)) | translate) }} + {% endif %}
diff --git a/tests/domain/test_task_orders.py b/tests/domain/test_task_orders.py index aa4bd476..d62a8634 100644 --- a/tests/domain/test_task_orders.py +++ b/tests/domain/test_task_orders.py @@ -16,6 +16,7 @@ def test_section_completion_status(): dict_keys = [k for k in TaskOrders.SECTIONS.keys()] section = dict_keys[0] attrs = TaskOrders.SECTIONS[section].copy() + attrs.remove("portfolio_name") task_order = TaskOrderFactory.create(**{k: None for k in attrs}) leftover = attrs.pop() From a92cbbaac6bec912eb0cacfa3717168f3d0dbb4a Mon Sep 17 00:00:00 2001 From: George Drummond Date: Fri, 1 Feb 2019 11:34:37 -0500 Subject: [PATCH 06/10] Display missing fields on review page --- templates/task_orders/new/review.html | 30 +++++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/templates/task_orders/new/review.html b/templates/task_orders/new/review.html index 57fb5e9f..37e0548e 100644 --- a/templates/task_orders/new/review.html +++ b/templates/task_orders/new/review.html @@ -67,13 +67,21 @@

{{ "task_orders.new.review.reporting"| translate }} {{ TOEditLink(screen=1, anchor="reporting") }}

- {% if task_order.app_migration %} - {{ ReviewField(("forms.task_order.app_migration.label" | translate), ("forms.task_order.app_migration.{}".format(task_order.app_migration) | translate), filter="removeHtml") }} - {% endif %} + {{ + ReviewField(("forms.task_order.app_migration.label" | translate), + ( + ("forms.task_order.app_migration.{}".format(task_order.app_migration) | translate) if task_order.app_migration else RequiredLabel() + ), + filter="removeHtml" + ) + }} - {% if task_order.native_apps %} - {{ ReviewField(("forms.task_order.native_apps.label" | translate), ("forms.task_order.native_apps.{}".format(task_order.native_apps))| translate) }} - {% endif %} + {{ + ReviewField(("forms.task_order.native_apps.label" | translate), + ( + ("forms.task_order.native_apps.{}".format(task_order.native_apps))| translate) if task_order.native_apps else RequiredLabel() + ) + }}

{{ "task_orders.new.review.complexity"| translate }}

@@ -109,9 +117,13 @@ {% endif %} - {% if task_order.team_experience %} - {{ ReviewField(("forms.task_order.team_experience.label" |translate), ("forms.task_order.team_experience.{}".format(task_order.team_experience)) | translate) }} - {% endif %} + {{ + ReviewField(("forms.task_order.team_experience.label" |translate), + ( + + ("forms.task_order.team_experience.{}".format(task_order.team_experience)) | translate) if task_order.team_experience else RequiredLabel() + ) + }}
From 4daadf59d2ec792b09730eb15a42eecc6c2b8b41 Mon Sep 17 00:00:00 2001 From: George Drummond Date: Fri, 1 Feb 2019 13:49:46 -0500 Subject: [PATCH 07/10] We don't need CLASSIFIED logic since its handled in mission_owner_sections --- atst/domain/task_orders.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py index 9d9d7219..d54cd249 100644 --- a/atst/domain/task_orders.py +++ b/atst/domain/task_orders.py @@ -99,12 +99,10 @@ class TaskOrders(object): failed = [] for attr in TaskOrders.SECTIONS[section]: - if not app.config.get("CLASSIFIED") and attr in ["clin_02", "clin_04"]: - pass - elif not getattr(task_order, attr): - failed.append(attr) - else: + if getattr(task_order, attr): passed.append(attr) + else: + failed.append(attr) if not failed: return "complete" From 0ace907fdf7461ab890e04d596fc12640142158c Mon Sep 17 00:00:00 2001 From: George Drummond Date: Fri, 1 Feb 2019 14:03:43 -0500 Subject: [PATCH 08/10] Clean up ReviewField fields --- templates/task_orders/new/review.html | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/templates/task_orders/new/review.html b/templates/task_orders/new/review.html index 37e0548e..e10d606b 100644 --- a/templates/task_orders/new/review.html +++ b/templates/task_orders/new/review.html @@ -68,18 +68,20 @@
{{ - ReviewField(("forms.task_order.app_migration.label" | 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 else RequiredLabel() - ), - filter="removeHtml" + ("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 else RequiredLabel() + ReviewField( + ("forms.task_order.native_apps.label" | translate), + ( + ("forms.task_order.native_apps.{}".format(task_order.native_apps) | translate) if task_order.native_apps + ) ) }}
@@ -118,10 +120,11 @@ {{ - ReviewField(("forms.task_order.team_experience.label" |translate), - ( - - ("forms.task_order.team_experience.{}".format(task_order.team_experience)) | translate) if task_order.team_experience else RequiredLabel() + ReviewField( + ("forms.task_order.team_experience.label" |translate), + ( + ("forms.task_order.team_experience.{}".format(task_order.team_experience) | translate) if task_order.team_experience + ) ) }} From f3b43cd8a166e8ecc9cc9f0d1c7f02fa59e8c7ca Mon Sep 17 00:00:00 2001 From: George Drummond Date: Fri, 1 Feb 2019 14:11:46 -0500 Subject: [PATCH 09/10] Remove InputRequired validator --- atst/forms/task_order.py | 32 ++++---------------------------- translations.yaml | 1 - 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index 85dd2bc6..c2c086e1 100644 --- a/atst/forms/task_order.py +++ b/atst/forms/task_order.py @@ -103,40 +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=[ - Optional(), - 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=[ - Optional(), - 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=[ - Optional(), - 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=[ - Optional(), - InputRequired( - message=(translate("forms.task_order.clin_validation_error")) - ), - ], + translate("forms.task_order.clin_04_label"), validators=[Optional()] ) diff --git a/translations.yaml b/translations.yaml index a6d68dd3..6b7ad7fa 100644 --- a/translations.yaml +++ b/translations.yaml @@ -222,7 +222,6 @@ forms: clin_02_label: 'CLIN 02: Classified' clin_03_label: 'CLIN 03: Unclassified' 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_04_label: 'CLIN 04: Classified (available soon)' oversight_first_name_label: First Name From 94f6a9afaaf5de05d3644d64dd0541fcc407e444 Mon Sep 17 00:00:00 2001 From: George Drummond Date: Fri, 1 Feb 2019 14:16:48 -0500 Subject: [PATCH 10/10] Fix specs --- atst/forms/task_order.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atst/forms/task_order.py b/atst/forms/task_order.py index c2c086e1..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, Required, InputRequired, Optional +from wtforms.validators import Length, Required, Optional from flask_wtf.file import FileAllowed from atst.forms.validators import IsNumber, PhoneNumber, RequiredIf