diff --git a/atst/domain/task_orders.py b/atst/domain/task_orders.py index 0c67e1d4..eceb01c3 100644 --- a/atst/domain/task_orders.py +++ b/atst/domain/task_orders.py @@ -64,10 +64,14 @@ class TaskOrders(BaseDomainClass): db.session.commit() @classmethod - def sort(cls, task_orders: [TaskOrder]) -> [TaskOrder]: - # Sorts a list of task orders on two keys: status (primary) and time_created (secondary) - 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)) + def sort_by_status(cls, task_orders): + by_status = {} + for status in SORT_ORDERING: + by_status[status] = [] + + for task_order in task_orders: + by_status[task_order.status].append(task_order) + return by_status @classmethod diff --git a/atst/models/task_order.py b/atst/models/task_order.py index 85bf363a..8bae6a7b 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -20,12 +20,7 @@ class Status(Enum): UNSIGNED = "Not signed" -SORT_ORDERING = { - status: order - for (order, status) in enumerate( - [Status.DRAFT, Status.ACTIVE, Status.UPCOMING, Status.EXPIRED, Status.UNSIGNED] - ) -} +SORT_ORDERING = [Status.ACTIVE, Status.DRAFT, Status.UPCOMING, Status.EXPIRED, Status.UNSIGNED] class TaskOrder(Base, mixins.TimestampsMixin): diff --git a/atst/routes/task_orders/index.py b/atst/routes/task_orders/index.py index a58ea8da..4c0adc07 100644 --- a/atst/routes/task_orders/index.py +++ b/atst/routes/task_orders/index.py @@ -28,14 +28,8 @@ def review_task_order(task_order_id): @user_can(Permissions.VIEW_PORTFOLIO_FUNDING, message="view portfolio funding") def portfolio_funding(portfolio_id): portfolio = Portfolios.get(g.current_user, portfolio_id) - task_orders = TaskOrders.sort(portfolio.task_orders) - label_colors = { - TaskOrderStatus.DRAFT: "warning", - TaskOrderStatus.ACTIVE: "success", - TaskOrderStatus.UPCOMING: "info", - TaskOrderStatus.EXPIRED: "error", - TaskOrderStatus.UNSIGNED: "purple", - } + task_orders = TaskOrders.sort_by_status(portfolio.task_orders) + # TODO: Get expended amount from the CSP return render_template( - "task_orders/index.html", task_orders=task_orders, label_colors=label_colors + "task_orders/index.html", task_orders=task_orders ) diff --git a/js/index.js b/js/index.js index a28c4868..fb5cdd6e 100644 --- a/js/index.js +++ b/js/index.js @@ -7,6 +7,8 @@ import Vue from 'vue/dist/vue' import VTooltip from 'v-tooltip' import stickybits from 'stickybits' +import Accordion from './components/accordion' +import AccordionList from './components/accordion_list' import dodlogin from './components/dodlogin' import optionsinput from './components/options_input' import multicheckboxinput from './components/multi_checkbox_input' @@ -29,7 +31,6 @@ import SemiCollapsibleText from './components/semi_collapsible_text' import ToForm from './components/forms/to_form' import ClinFields from './components/clin_fields' import PopDateRange from './components/pop_date_range' -import Accordion from './components/accordion' import ToggleMenu from './components/toggle_menu' Vue.config.productionTip = false @@ -42,6 +43,7 @@ const app = new Vue({ el: '#app-root', components: { Accordion, + AccordionList, dodlogin, toggler, optionsinput, diff --git a/js/mixins/toggle.js b/js/mixins/toggle.js index d891eb02..3e155dd3 100644 --- a/js/mixins/toggle.js +++ b/js/mixins/toggle.js @@ -17,6 +17,7 @@ export default { methods: { toggle: function(e) { e.preventDefault() + e.stopPropagation() this.isVisible = !this.isVisible }, }, diff --git a/templates/task_orders/index.html b/templates/task_orders/index.html index 0c319403..9e867bde 100644 --- a/templates/task_orders/index.html +++ b/templates/task_orders/index.html @@ -13,7 +13,6 @@ {% macro TaskOrderList(task_orders, status) %} - {% set status = "All Task Orders" %}
{% call Accordion(title=status, id=status, heading_tag="h4") %} {% for task_order in task_orders %} @@ -63,7 +62,9 @@
{% if task_orders %} - {{ TaskOrderList(task_orders) }} + {% for status, to_list in task_orders.items() %} + {{ TaskOrderList(to_list, status.value) }} + {% endfor %} {% else %} {{ EmptyState( header="task_orders.empty_state.header"|translate, diff --git a/tests/domain/test_task_orders.py b/tests/domain/test_task_orders.py index 8b1eb724..d2005c50 100644 --- a/tests/domain/test_task_orders.py +++ b/tests/domain/test_task_orders.py @@ -3,78 +3,11 @@ from datetime import date, timedelta from decimal import Decimal from atst.domain.task_orders import TaskOrders -from atst.models import Attachment, TaskOrder +from atst.models import Attachment +from atst.models.task_order import TaskOrder, SORT_ORDERING, Status from tests.factories import TaskOrderFactory, CLINFactory, PortfolioFactory -def test_task_order_sorting(): - """ - Task orders should be listed first by status, and then by time_created. - """ - - today = date.today() - yesterday = today - timedelta(days=1) - future = today + timedelta(days=100) - - task_orders = [ - # Draft - TaskOrderFactory.create(pdf=None), - TaskOrderFactory.create(pdf=None), - TaskOrderFactory.create(pdf=None), - # Active - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=yesterday, end_date=future)], - ), - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=yesterday, end_date=future)], - ), - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=yesterday, end_date=future)], - ), - # Upcoming - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=future, end_date=future)], - ), - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=future, end_date=future)], - ), - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=future, end_date=future)], - ), - # Expired - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)], - ), - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)], - ), - TaskOrderFactory.create( - signed_at=yesterday, - clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)], - ), - # Unsigned - TaskOrderFactory.create( - clins=[CLINFactory.create(start_date=today, end_date=today)] - ), - TaskOrderFactory.create( - clins=[CLINFactory.create(start_date=today, end_date=today)] - ), - TaskOrderFactory.create( - clins=[CLINFactory.create(start_date=today, end_date=today)] - ), - ] - - assert TaskOrders.sort(task_orders) == task_orders - - def test_create_adds_clins(): portfolio = PortfolioFactory.create() clins = [ @@ -177,3 +110,47 @@ def test_delete_task_order_with_clins(session): assert not session.query( session.query(TaskOrder).filter_by(id=task_order.id).exists() ).scalar() + + +def test_task_order_sort_by_status(): + today = date.today() + yesterday = today - timedelta(days=1) + future = today + timedelta(days=100) + + initial_to_list = [ + # Draft + TaskOrderFactory.create(pdf=None), + TaskOrderFactory.create(pdf=None), + TaskOrderFactory.create(pdf=None), + # Active + TaskOrderFactory.create( + signed_at=yesterday, + clins=[CLINFactory.create(start_date=yesterday, end_date=future)], + ), + # Upcoming + TaskOrderFactory.create( + signed_at=yesterday, + clins=[CLINFactory.create(start_date=future, end_date=future)], + ), + # Expired + TaskOrderFactory.create( + signed_at=yesterday, + clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)], + ), + TaskOrderFactory.create( + signed_at=yesterday, + clins=[CLINFactory.create(start_date=yesterday, end_date=yesterday)], + ), + # Unsigned + TaskOrderFactory.create( + clins=[CLINFactory.create(start_date=today, end_date=today)] + ), + ] + + sorted_by_status = TaskOrders.sort_by_status(initial_to_list) + assert len(sorted_by_status[Status.DRAFT]) == 3 + assert len(sorted_by_status[Status.ACTIVE]) == 1 + assert len(sorted_by_status[Status.UPCOMING]) == 1 + assert len(sorted_by_status[Status.EXPIRED]) == 2 + assert len(sorted_by_status[Status.UNSIGNED]) == 1 + assert list(sorted_by_status.keys()) == SORT_ORDERING