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