diff --git a/atst/models/portfolio.py b/atst/models/portfolio.py index ffa674c3..c006dd37 100644 --- a/atst/models/portfolio.py +++ b/atst/models/portfolio.py @@ -100,6 +100,16 @@ class Portfolio( (task_order.total_obligated_funds for task_order in self.active_task_orders) ) + @property + def upcoming_obligated_funds(self): + return sum( + ( + task_order.total_obligated_funds + for task_order in self.task_orders + if task_order.is_upcoming + ) + ) + @property def funding_duration(self): """ diff --git a/atst/models/task_order.py b/atst/models/task_order.py index 3ab493a9..c6dda237 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -87,6 +87,10 @@ class TaskOrder(Base, mixins.TimestampsMixin): def is_expired(self): return self.status == Status.EXPIRED + @property + def is_upcoming(self): + return self.status == Status.UPCOMING + @property def clins_are_completed(self): return all([len(self.clins), (clin.is_completed for clin in self.clins)]) diff --git a/tests/models/test_portfolio.py b/tests/models/test_portfolio.py index af082876..033847a4 100644 --- a/tests/models/test_portfolio.py +++ b/tests/models/test_portfolio.py @@ -7,6 +7,51 @@ from tests.factories import ( random_past_date, ) import datetime +import pendulum +from decimal import Decimal +import pytest + + +@pytest.fixture(scope="function") +def upcoming_task_order(): + return dict( + signed_at=pendulum.today().subtract(days=3), + create_clins=[ + dict( + start_date=pendulum.today().add(days=2), + end_date=pendulum.today().add(days=3), + obligated_amount=Decimal(700.0), + ) + ], + ) + + +@pytest.fixture(scope="function") +def current_task_order(): + return dict( + signed_at=pendulum.today().subtract(days=3), + create_clins=[ + dict( + start_date=pendulum.today().subtract(days=1), + end_date=pendulum.today().add(days=1), + obligated_amount=Decimal(1000.0), + ) + ], + ) + + +@pytest.fixture(scope="function") +def past_task_order(): + return dict( + signed_at=pendulum.today().subtract(days=3), + create_clins=[ + dict( + start_date=pendulum.today().subtract(days=3), + end_date=pendulum.today().subtract(days=2), + obligated_amount=Decimal(500.0), + ) + ], + ) def test_portfolio_applications_excludes_deleted(): @@ -85,3 +130,28 @@ def test_active_task_orders(session): portfolio=portfolio, signed_at=random_past_date(), clins=[CLINFactory.create()] ) assert len(portfolio.active_task_orders) == 1 + + +class TestUpcomingObligatedFunds: + """ + Tests the upcoming_obligated_funds property + """ + + def test_no_task_orders(self): + portfolio = PortfolioFactory() + assert portfolio.upcoming_obligated_funds == Decimal(0) + + def test_with_upcoming(self, upcoming_task_order): + portfolio = PortfolioFactory( + task_orders=[upcoming_task_order, upcoming_task_order] + ) + assert portfolio.upcoming_obligated_funds == Decimal(1400.0) + + def test_with_others( + self, past_task_order, current_task_order, upcoming_task_order + ): + portfolio = PortfolioFactory( + task_orders=[past_task_order, current_task_order, upcoming_task_order] + ) + # Only sums the upcoming task order + assert portfolio.upcoming_obligated_funds == Decimal(700.0)