diff --git a/alembic/versions/fda6bd7e1b65_clin_delete_cascade.py b/alembic/versions/fda6bd7e1b65_clin_delete_cascade.py new file mode 100644 index 00000000..18b1bf7a --- /dev/null +++ b/alembic/versions/fda6bd7e1b65_clin_delete_cascade.py @@ -0,0 +1,26 @@ +"""clin delete cascade + +Revision ID: fda6bd7e1b65 +Revises: e0c6eb21771f +Create Date: 2019-08-07 16:37:02.451277 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'fda6bd7e1b65' +down_revision = 'e0c6eb21771f' +branch_labels = None +depends_on = None + + +def upgrade(): + op.drop_constraint("clins_task_order_id_fkey", "clins") + op.create_foreign_key("clins_task_order_id_fkey", "clins", "task_orders", ["task_order_id"], ["id"], ondelete="cascade") + + +def downgrade(): + op.drop_constraint("clins_task_order_id_fkey", "clins") + op.create_foreign_key("clins_task_order_id_fkey", "clins", "task_orders", ["task_order_id"], ["id"], ondelete="no action") diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py index 94343c7c..ee470395 100644 --- a/atst/domain/task_orders.py +++ b/atst/domain/task_orders.py @@ -71,3 +71,9 @@ class TaskOrders(BaseDomainClass): by_time_created = sorted(task_orders, key=lambda to: to.time_created) by_status = sorted(by_time_created, key=lambda to: SORT_ORDERING.get(to.status)) return by_status + + @classmethod + def delete(cls, task_order_id): + task_order = TaskOrders.get(task_order_id) + db.session.delete(task_order) + db.session.commit() diff --git a/atst/models/task_order.py b/atst/models/task_order.py index c7a9b906..8d2f03fc 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -43,7 +43,9 @@ class TaskOrder(Base, mixins.TimestampsMixin): signer_dod_id = Column(String) signed_at = Column(DateTime) - clins = relationship("CLIN", back_populates="task_order") + clins = relationship( + "CLIN", back_populates="task_order", cascade="all, delete-orphan" + ) @hybrid_property def pdf(self): diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index 356fbcc4..aca1c543 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -39,6 +39,7 @@ def render_task_orders_edit(template, portfolio_id=None, task_order_id=None, for "task_orders.cancel_edit", task_order_id=task_order_id, portfolio_id=portfolio_id, + save=False, ) return render_template(template, **render_args) @@ -137,7 +138,9 @@ def submit_form_step_one_add_pdf(portfolio_id=None, task_order_id=None): @task_orders_bp.route("/task_orders//form/cancel", methods=["POST"]) @user_can(Permissions.CREATE_TASK_ORDER, message="cancel task order form") def cancel_edit(task_order_id=None, portfolio_id=None): - save = http_request.args.get("save", False) + # Either save the currently entered data, or delete the TO + save = http_request.args.get("save", "True").lower() == "true" + if save: form_data = {**http_request.form} form = None @@ -155,6 +158,8 @@ def cancel_edit(task_order_id=None, portfolio_id=None): task_order = TaskOrders.create( g.current_user, portfolio_id, **form.data ) + elif not save and task_order_id: + TaskOrders.delete(task_order_id) return redirect( url_for("task_orders.portfolio_funding", portfolio_id=g.portfolio.id) diff --git a/tests/domain/test_task_orders.py b/tests/domain/test_task_orders.py index 774a215b..4c7c21c9 100644 --- a/tests/domain/test_task_orders.py +++ b/tests/domain/test_task_orders.py @@ -3,7 +3,7 @@ from datetime import date, timedelta from decimal import Decimal from atst.domain.task_orders import TaskOrders -from atst.models.attachment import Attachment +from atst.models import Attachment, TaskOrder from tests.factories import TaskOrderFactory, CLINFactory, PortfolioFactory @@ -168,3 +168,12 @@ def test_update_does_not_duplicate_clins(): assert len(task_order.clins) == 2 for clin in task_order.clins: assert clin.number != "456" + + +def test_delete_task_order_with_clins(session): + task_order = TaskOrderFactory.create(create_clins=[1, 2, 3]) + TaskOrders.delete(task_order.id) + + assert not session.query( + session.query(TaskOrder).filter_by(id=task_order.id).exists() + ).scalar() diff --git a/tests/routes/task_orders/test_new.py b/tests/routes/task_orders/test_new.py index 1e13e126..478baedf 100644 --- a/tests/routes/task_orders/test_new.py +++ b/tests/routes/task_orders/test_new.py @@ -334,22 +334,20 @@ def test_cancel_can_create_new_to(client, user_session, portfolio): assert response.status_code == 302 -def test_cancel_edit_does_not_save_invalid_form_input(client, user_session, session): +def test_cancel_edit_causes_to_to_be_deleted(client, user_session, session): task_order = TaskOrderFactory.create() user_session(task_order.portfolio.owner) - bad_data = {"clins-0-jedi_clin_type": "foo"} response = client.post( - url_for("task_orders.cancel_edit", task_order_id=task_order.id, save=True), - data=bad_data, + url_for("task_orders.cancel_edit", task_order_id=task_order.id, save=False), + data={}, ) assert response.status_code == 302 - # CLINs should be unchanged - updated_task_order = session.query(TaskOrder).get(task_order.id) - assert updated_task_order.clins == task_order.clins + # TO should be deleted + assert session.query(TaskOrder).get(task_order.id) is None -def test_cancel_edit_on_invalid_input_does_not_flash( +def test_cancel_edit_and_save_with_invalid_input_does_not_flash( app, client, user_session, session ): task_order = TaskOrderFactory.create() @@ -365,20 +363,6 @@ def test_cancel_edit_on_invalid_input_does_not_flash( assert len(get_flashed_messages()) == 0 -def test_cancel_edit_without_saving(client, user_session, session): - task_order = TaskOrderFactory.create(number=None) - user_session(task_order.portfolio.owner) - response = client.post( - url_for("task_orders.cancel_edit", task_order_id=task_order.id), - data={"number": "7643906432984"}, - ) - assert response.status_code == 302 - - # TO number should be unchanged - updated_task_order = session.query(TaskOrder).get(task_order.id) - assert updated_task_order.number is None - - @pytest.mark.skip(reason="Reevaluate how form handles invalid data") def test_task_orders_update_invalid_data(client, user_session, portfolio): user_session(portfolio.owner)