Implement new CLIN-based TO statuses
This commit is contained in:
parent
7b8ccbf145
commit
8ecf112c48
@ -1,5 +1,5 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from datetime import date
|
from datetime import date, datetime
|
||||||
|
|
||||||
from sqlalchemy import Column, DateTime, ForeignKey, String
|
from sqlalchemy import Column, DateTime, ForeignKey, String
|
||||||
from sqlalchemy.ext.hybrid import hybrid_property
|
from sqlalchemy.ext.hybrid import hybrid_property
|
||||||
@ -15,6 +15,9 @@ class Status(Enum):
|
|||||||
PENDING = "Pending"
|
PENDING = "Pending"
|
||||||
ACTIVE = "Active"
|
ACTIVE = "Active"
|
||||||
EXPIRED = "Expired"
|
EXPIRED = "Expired"
|
||||||
|
DRAFT = "Draft"
|
||||||
|
UPCOMING = "Upcoming"
|
||||||
|
UNSIGNED = "Unsigned"
|
||||||
|
|
||||||
|
|
||||||
class TaskOrder(Base, mixins.TimestampsMixin):
|
class TaskOrder(Base, mixins.TimestampsMixin):
|
||||||
@ -62,19 +65,36 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
def is_expired(self):
|
def is_expired(self):
|
||||||
return self.status == Status.EXPIRED
|
return self.status == Status.EXPIRED
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_completed(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_signed(self):
|
||||||
|
return self.signed_at is not None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status(self):
|
def status(self):
|
||||||
# TODO: fix task order -- implement correctly using CLINs
|
today = date.today()
|
||||||
# Faked for display purposes
|
|
||||||
return Status.ACTIVE
|
if not self.is_completed and not self.is_signed:
|
||||||
|
return Status.DRAFT
|
||||||
|
elif self.is_completed and not self.is_signed:
|
||||||
|
return Status.UNSIGNED
|
||||||
|
elif today < self.start_date:
|
||||||
|
return Status.UPCOMING
|
||||||
|
elif today >= self.end_date:
|
||||||
|
return Status.EXPIRED
|
||||||
|
elif self.start_date <= today < self.end_date:
|
||||||
|
return Status.ACTIVE
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def start_date(self):
|
def start_date(self):
|
||||||
return min(c.start_date for c in self.clins)
|
return min((c.start_date for c in self.clins), default=None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def end_date(self):
|
def end_date(self):
|
||||||
return max(c.end_date for c in self.clins)
|
return max((c.end_date for c in self.clins), default=None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def days_to_expiration(self):
|
def days_to_expiration(self):
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
from werkzeug.datastructures import FileStorage
|
from werkzeug.datastructures import FileStorage
|
||||||
import pytest
|
import pytest
|
||||||
from datetime import date
|
from datetime import date, datetime
|
||||||
|
from unittest.mock import Mock, patch, PropertyMock
|
||||||
|
import pendulum
|
||||||
|
|
||||||
from atst.models import *
|
from atst.models import *
|
||||||
from atst.models.clin import JEDICLINType
|
from atst.models.clin import JEDICLINType
|
||||||
@ -48,26 +50,74 @@ class TestPeriodOfPerformance:
|
|||||||
|
|
||||||
|
|
||||||
class TestTaskOrderStatus:
|
class TestTaskOrderStatus:
|
||||||
@pytest.mark.skip(reason="Reimplement after adding CLINs")
|
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||||
def test_started_status(self):
|
@patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)
|
||||||
|
def test_draft_status(self, is_signed, is_completed):
|
||||||
|
# Given that I have a TO that is neither completed nor signed
|
||||||
to = TaskOrder()
|
to = TaskOrder()
|
||||||
assert to.status == Status.STARTED
|
is_signed.return_value = False
|
||||||
|
is_completed.return_value = False
|
||||||
|
|
||||||
@pytest.mark.skip(reason="See if still needed after implementing CLINs")
|
assert to.status == Status.DRAFT
|
||||||
def test_pending_status(self):
|
|
||||||
to = TaskOrder(number="42")
|
|
||||||
assert to.status == Status.PENDING
|
|
||||||
|
|
||||||
@pytest.mark.skip(reason="See if still needed after implementing CLINs")
|
@patch("atst.models.TaskOrder.end_date", new_callable=PropertyMock)
|
||||||
def test_active_status(self):
|
@patch("atst.models.TaskOrder.start_date", new_callable=PropertyMock)
|
||||||
to = TaskOrder(number="42")
|
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||||
|
@patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)
|
||||||
|
def test_active_status(self, is_signed, is_completed, start_date, end_date):
|
||||||
|
# Given that I have a signed TO and today is within its start_date and end_date
|
||||||
|
today = pendulum.today().date()
|
||||||
|
to = TaskOrder()
|
||||||
|
|
||||||
|
start_date.return_value = today.subtract(days=1)
|
||||||
|
end_date.return_value = today.add(days=1)
|
||||||
|
is_signed.return_value = True
|
||||||
|
is_completed.return_value = True
|
||||||
|
|
||||||
|
# Its status should be active
|
||||||
assert to.status == Status.ACTIVE
|
assert to.status == Status.ACTIVE
|
||||||
|
|
||||||
@pytest.mark.skip(reason="See if still needed after implementing CLINs")
|
@patch("atst.models.TaskOrder.end_date", new_callable=PropertyMock)
|
||||||
def test_expired_status(self):
|
@patch("atst.models.TaskOrder.start_date", new_callable=PropertyMock)
|
||||||
to = TaskOrder(number="42")
|
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||||
|
@patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)
|
||||||
|
def test_upcoming_status(self, is_signed, is_completed, start_date, end_date):
|
||||||
|
# Given that I have a signed TO and today is before its start_date
|
||||||
|
to = TaskOrder()
|
||||||
|
start_date.return_value = pendulum.today().add(days=1).date()
|
||||||
|
end_date.return_value = pendulum.today().add(days=2).date()
|
||||||
|
is_signed.return_value = True
|
||||||
|
is_completed.return_value = True
|
||||||
|
|
||||||
|
# Its status should be upcoming
|
||||||
|
assert to.status == Status.UPCOMING
|
||||||
|
|
||||||
|
@patch("atst.models.TaskOrder.start_date", new_callable=PropertyMock)
|
||||||
|
@patch("atst.models.TaskOrder.end_date", new_callable=PropertyMock)
|
||||||
|
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||||
|
@patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)
|
||||||
|
def test_expired_status(self, is_signed, is_completed, end_date, start_date):
|
||||||
|
# Given that I have a signed TO and today is after its expiration date
|
||||||
|
to = TaskOrder()
|
||||||
|
end_date.return_value = pendulum.today().subtract(days=1).date()
|
||||||
|
start_date.return_value = pendulum.today().subtract(days=2).date()
|
||||||
|
is_signed.return_value = True
|
||||||
|
is_completed.return_value = True
|
||||||
|
|
||||||
|
# Its status should be expired
|
||||||
assert to.status == Status.EXPIRED
|
assert to.status == Status.EXPIRED
|
||||||
|
|
||||||
|
@patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock)
|
||||||
|
@patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)
|
||||||
|
def test_unsigned_status(self, is_signed, is_completed):
|
||||||
|
# Given that I have a TO that is completed but not signed
|
||||||
|
to = TaskOrder(signed_at=pendulum.now().subtract(days=1))
|
||||||
|
is_completed.return_value = True
|
||||||
|
is_signed.return_value = False
|
||||||
|
|
||||||
|
# Its status should be unsigned
|
||||||
|
assert to.status == Status.UNSIGNED
|
||||||
|
|
||||||
|
|
||||||
class TestBudget:
|
class TestBudget:
|
||||||
def test_total_contract_amount(self):
|
def test_total_contract_amount(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user