Update TO route helper function to catch error and display flash message when a user tries to save a TO with an existing number.

Update TaskOrderForm so that it converts empty string for number into None, this was causing an issue where new TOs were being saved with an empty string for the number, which violated the unique constraint.
This commit is contained in:
leigh-mil 2019-12-12 14:21:30 -05:00
parent 9caef2883a
commit 78ef47f649
6 changed files with 70 additions and 20 deletions

View File

@ -142,6 +142,14 @@ class TaskOrderForm(BaseForm):
) )
clins = FieldList(FormField(CLINForm)) clins = FieldList(FormField(CLINForm))
@property
def data(self):
_data = super().data
if _data["number"] == "":
_data["number"] = None
return _data
class SignatureForm(BaseForm): class SignatureForm(BaseForm):
signature = BooleanField( signature = BooleanField(

View File

@ -10,7 +10,7 @@ from flask import (
from .blueprint import task_orders_bp from .blueprint import task_orders_bp
from atst.domain.authz.decorator import user_can_access_decorator as user_can from atst.domain.authz.decorator import user_can_access_decorator as user_can
from atst.domain.exceptions import NoAccessError from atst.domain.exceptions import NoAccessError, AlreadyExistsError
from atst.domain.task_orders import TaskOrders from atst.domain.task_orders import TaskOrders
from atst.forms.task_order import TaskOrderForm, SignatureForm from atst.forms.task_order import TaskOrderForm, SignatureForm
from atst.models.permissions import Permissions from atst.models.permissions import Permissions
@ -50,7 +50,26 @@ def render_task_orders_edit(
return render_template(template, **render_args) return render_template(template, **render_args)
def update_task_order( def update_task_order(form, portfolio_id=None, task_order_id=None, flash_invalid=True):
if form.validate(flash_invalid=flash_invalid):
task_order = None
try:
if task_order_id:
task_order = TaskOrders.update(task_order_id, **form.data)
portfolio_id = task_order.portfolio_id
else:
task_order = TaskOrders.create(portfolio_id, **form.data)
return task_order
except AlreadyExistsError:
flash("task_order_number_error", to_number=form.data["number"])
return False
else:
return False
def update_and_render_next(
form_data, next_page, current_template, portfolio_id=None, task_order_id=None form_data, next_page, current_template, portfolio_id=None, task_order_id=None
): ):
form = None form = None
@ -60,14 +79,8 @@ def update_task_order(
else: else:
form = TaskOrderForm(form_data) form = TaskOrderForm(form_data)
if form.validate(): task_order = update_task_order(form, portfolio_id, task_order_id)
task_order = None if task_order:
if task_order_id:
task_order = TaskOrders.update(task_order_id, **form.data)
portfolio_id = task_order.portfolio_id
else:
task_order = TaskOrders.create(portfolio_id, **form.data)
return redirect(url_for(next_page, task_order_id=task_order.id)) return redirect(url_for(next_page, task_order_id=task_order.id))
else: else:
return ( return (
@ -149,7 +162,7 @@ def submit_form_step_one_add_pdf(portfolio_id=None, task_order_id=None):
next_page = "task_orders.form_step_two_add_number" next_page = "task_orders.form_step_two_add_number"
current_template = "task_orders/step_1.html" current_template = "task_orders/step_1.html"
return update_task_order( return update_and_render_next(
form_data, form_data,
next_page, next_page,
current_template, current_template,
@ -176,12 +189,8 @@ def cancel_edit(task_order_id=None, portfolio_id=None):
else: else:
form = TaskOrderForm(form_data) form = TaskOrderForm(form_data)
if form.validate(flash_invalid=False): update_task_order(form, portfolio_id, task_order_id, flash_invalid=False)
task_order = None
if task_order_id:
task_order = TaskOrders.update(task_order_id, **form.data)
else:
task_order = TaskOrders.create(portfolio_id, **form.data)
elif not save and task_order_id: elif not save and task_order_id:
TaskOrders.delete(task_order_id) TaskOrders.delete(task_order_id)
@ -205,7 +214,7 @@ def submit_form_step_two_add_number(task_order_id):
next_page = "task_orders.form_step_three_add_clins" next_page = "task_orders.form_step_three_add_clins"
current_template = "task_orders/step_2.html" current_template = "task_orders/step_2.html"
return update_task_order( return update_and_render_next(
form_data, next_page, current_template, task_order_id=task_order_id form_data, next_page, current_template, task_order_id=task_order_id
) )
@ -225,7 +234,7 @@ def submit_form_step_three_add_clins(task_order_id):
next_page = "task_orders.form_step_four_review" next_page = "task_orders.form_step_four_review"
current_template = "task_orders/step_3.html" current_template = "task_orders/step_3.html"
return update_task_order( return update_and_render_next(
form_data, next_page, current_template, task_order_id=task_order_id form_data, next_page, current_template, task_order_id=task_order_id
) )

View File

@ -165,6 +165,11 @@ MESSAGES = {
"message_template": translate("task_orders.form.draft_alert_message"), "message_template": translate("task_orders.form.draft_alert_message"),
"category": "warning", "category": "warning",
}, },
"task_order_number_error": {
"title_template": "",
"message_template": """{{ 'flash.task_order_number_error.message' | translate({ 'to_number': to_number }) }}""",
"category": "error",
},
"task_order_submitted": { "task_order_submitted": {
"title_template": "Your Task Order has been uploaded successfully.", "title_template": "Your Task Order has been uploaded successfully.",
"message_template": """ "message_template": """

View File

@ -2,7 +2,7 @@ import datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from flask import current_app as app from flask import current_app as app
from atst.forms.task_order import CLINForm from atst.forms.task_order import CLINForm, TaskOrderForm
from atst.models import JEDICLINType from atst.models import JEDICLINType
from atst.utils.localization import translate from atst.utils.localization import translate
@ -106,3 +106,9 @@ def test_clin_form_dollar_amounts_out_of_range():
assert ( assert (
translate("forms.task_order.clin_funding_errors.funding_range_error") translate("forms.task_order.clin_funding_errors.funding_range_error")
) in invalid_clin_form.obligated_amount.errors ) in invalid_clin_form.obligated_amount.errors
def test_no_number():
http_request_form_data = {}
form = TaskOrderForm(http_request_form_data)
assert form.data["number"] is None

View File

@ -170,6 +170,26 @@ def test_task_orders_submit_form_step_two_add_number(client, user_session, task_
assert task_order.number == "1234567890" assert task_order.number == "1234567890"
def test_task_orders_submit_form_step_two_enforces_unique_number(
client, user_session, task_order, session
):
number = "1234567890123"
dupe_task_order = TaskOrderFactory.create(number=number)
portfolio = task_order.portfolio
user_session(task_order.portfolio.owner)
form_data = {"number": number}
session.begin_nested()
response = client.post(
url_for(
"task_orders.submit_form_step_two_add_number", task_order_id=task_order.id
),
data=form_data,
)
session.rollback()
assert response.status_code == 400
def test_task_orders_submit_form_step_two_add_number_existing_to( def test_task_orders_submit_form_step_two_add_number_existing_to(
client, user_session, task_order client, user_session, task_order
): ):

View File

@ -123,6 +123,8 @@ flash:
new_ppoc_message: 'You have successfully added {ppoc_name} as the primary point of contact. You are no longer the PPoC.' new_ppoc_message: 'You have successfully added {ppoc_name} as the primary point of contact. You are no longer the PPoC.'
new_ppoc_title: Primary point of contact updated new_ppoc_title: Primary point of contact updated
success: Success! success: Success!
task_order_number_error:
message: 'The TO number has already been entered for a JEDI task order #{to_number}. Please double-check the TO number you are entering. If you believe this is in error, please contact support@cloud.mil.'
new_application_member: new_application_member:
title: "{user_name}'s invitation has been sent" title: "{user_name}'s invitation has been sent"
message: "{user_name}'s access to this Application is pending until they sign in for the first time." message: "{user_name}'s access to this Application is pending until they sign in for the first time."