From 6af50b78b054a844f51b41ccdb4d941633116edf Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 4 Sep 2018 12:47:17 -0400 Subject: [PATCH 1/5] Implement Request.last_submission_date --- atst/domain/requests.py | 2 ++ atst/models/request.py | 13 +++++++++++++ atst/models/request_status_event.py | 1 + tests/domain/test_requests.py | 9 +++++++++ 4 files changed, 25 insertions(+) diff --git a/atst/domain/requests.py b/atst/domain/requests.py index cc577d09..d44be200 100644 --- a/atst/domain/requests.py +++ b/atst/domain/requests.py @@ -87,6 +87,8 @@ class Requests(object): @classmethod def submit(cls, request): + request = Requests.set_status(request, RequestStatus.SUBMITTED) + new_status = None if Requests.should_auto_approve(request): new_status = RequestStatus.PENDING_FINANCIAL_VERIFICATION diff --git a/atst/models/request.py b/atst/models/request.py index e653edf8..419e8156 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -5,6 +5,10 @@ from sqlalchemy.orm import relationship from atst.models import Base from atst.models.types import Id +from atst.models.request_status_event import RequestStatus + +def first_or_none(predicate, lst): + return next((x for x in lst if predicate(x)), None,) class Request(Base): @@ -47,3 +51,12 @@ class Request(Base): if self.task_order: return self.task_order.verified return False + + @property + def last_submission_date(self): + def _is_submission(status_event): + return status_event.new_status == RequestStatus.SUBMITTED + + last_submission = first_or_none(_is_submission, reversed(self.status_events)) + if last_submission: + return last_submission.time_created diff --git a/atst/models/request_status_event.py b/atst/models/request_status_event.py index 810a4427..bf95f5ce 100644 --- a/atst/models/request_status_event.py +++ b/atst/models/request_status_event.py @@ -10,6 +10,7 @@ from atst.models.types import Id class RequestStatus(Enum): STARTED = "Started" + SUBMITTED = "Submitted" PENDING_FINANCIAL_VERIFICATION = "Pending Financial Verification" PENDING_CCPO_APPROVAL = "Pending CCPO Approval" CHANGES_REQUESTED = "Changes Requested" diff --git a/tests/domain/test_requests.py b/tests/domain/test_requests.py index 38a76e93..6e9e2d5d 100644 --- a/tests/domain/test_requests.py +++ b/tests/domain/test_requests.py @@ -70,6 +70,15 @@ def test_should_allow_submission(new_request): assert not Requests.should_allow_submission(new_request) +def test_request_knows_its_last_submission_date(new_request): + submitted_request = Requests.submit(new_request) + assert submitted_request.last_submission_date + + +def test_request_knows_if_it_has_no_last_submission_date(new_request): + assert new_request.last_submission_date is None + + def test_exists(session): user_allowed = UserFactory.create() user_denied = UserFactory.create() From 6bfbaea867d74501a69ec8f7936683654fad1f4b Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 4 Sep 2018 12:50:44 -0400 Subject: [PATCH 2/5] Factor out first_or_none --- atst/models/request.py | 4 +--- atst/models/workspace.py | 13 +++++-------- atst/utils.py | 2 ++ 3 files changed, 8 insertions(+), 11 deletions(-) create mode 100644 atst/utils.py diff --git a/atst/models/request.py b/atst/models/request.py index 419e8156..cf4f6cdd 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -6,9 +6,7 @@ from sqlalchemy.orm import relationship from atst.models import Base from atst.models.types import Id from atst.models.request_status_event import RequestStatus - -def first_or_none(predicate, lst): - return next((x for x in lst if predicate(x)), None,) +from atst.utils import first_or_none class Request(Base): diff --git a/atst/models/workspace.py b/atst/models/workspace.py index 8f6c58d9..aca024a4 100644 --- a/atst/models/workspace.py +++ b/atst/models/workspace.py @@ -4,6 +4,7 @@ from sqlalchemy.orm import relationship from atst.models import Base from atst.models.types import Id from atst.models.mixins import TimestampsMixin +from atst.utils import first_or_none MOCK_MEMBERS = [ @@ -48,14 +49,10 @@ class Workspace(Base, TimestampsMixin): @property def owner(self): - return next( - ( - workspace_role.user - for workspace_role in self.roles - if workspace_role.role.name == "owner" - ), - None, - ) + def _is_workspace_owner(workspace_role): + return workspace_role.role.name == "owner" + + return first_or_none(_is_workspace_owner, self.roles) @property def users(self): diff --git a/atst/utils.py b/atst/utils.py new file mode 100644 index 00000000..f836cea2 --- /dev/null +++ b/atst/utils.py @@ -0,0 +1,2 @@ +def first_or_none(predicate, lst): + return next((x for x in lst if predicate(x)), None,) From 3af630e4dd6d2bce78e3a17b93801d7b97e9c242 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 4 Sep 2018 13:09:27 -0400 Subject: [PATCH 3/5] Return pendulum instance from last_submission_timestamp --- atst/models/request.py | 6 ++++-- tests/domain/test_requests.py | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/atst/models/request.py b/atst/models/request.py index cf4f6cdd..466c6d91 100644 --- a/atst/models/request.py +++ b/atst/models/request.py @@ -2,6 +2,7 @@ from sqlalchemy import Column, func, ForeignKey from sqlalchemy.types import DateTime from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import relationship +import pendulum from atst.models import Base from atst.models.types import Id @@ -51,10 +52,11 @@ class Request(Base): return False @property - def last_submission_date(self): + def last_submission_timestamp(self): def _is_submission(status_event): return status_event.new_status == RequestStatus.SUBMITTED last_submission = first_or_none(_is_submission, reversed(self.status_events)) if last_submission: - return last_submission.time_created + return pendulum.instance(last_submission.time_created) + return None diff --git a/tests/domain/test_requests.py b/tests/domain/test_requests.py index 6e9e2d5d..dfa6018a 100644 --- a/tests/domain/test_requests.py +++ b/tests/domain/test_requests.py @@ -70,13 +70,13 @@ def test_should_allow_submission(new_request): assert not Requests.should_allow_submission(new_request) -def test_request_knows_its_last_submission_date(new_request): +def test_request_knows_its_last_submission_timestamp(new_request): submitted_request = Requests.submit(new_request) - assert submitted_request.last_submission_date + assert submitted_request.last_submission_timestamp -def test_request_knows_if_it_has_no_last_submission_date(new_request): - assert new_request.last_submission_date is None +def test_request_knows_if_it_has_no_last_submission_timestamp(new_request): + assert new_request.last_submission_timestamp is None def test_exists(session): From 0af7fb4573cde2b951af2db275e18ba017364b81 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 4 Sep 2018 13:09:48 -0400 Subject: [PATCH 4/5] Use last_submission_timestamp in requests index --- atst/routes/requests/index.py | 7 ++++++- atst/utils.py | 2 +- templates/requests.html | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/atst/routes/requests/index.py b/atst/routes/requests/index.py index e6606d91..c9b15705 100644 --- a/atst/routes/requests/index.py +++ b/atst/routes/requests/index.py @@ -11,6 +11,11 @@ def map_request(request): is_new = time_created.add(days=1) > pendulum.now() app_count = request.body.get("details_of_use", {}).get("num_software_systems", 0) annual_usage = request.annual_spend + last_submission_timestamp = ( + request.last_submission_timestamp.format("M/DD/YYY") + if request.last_submission_timestamp + else "-" + ) if Requests.is_pending_financial_verification(request): edit_link = url_for("requests.financial_verification", request_id=request.id) @@ -27,7 +32,7 @@ def map_request(request): "is_new": is_new, "status": request.status_displayname, "app_count": app_count, - "date": time_created.format("M/DD/YYYY"), + "last_submission_timestamp": last_submission_timestamp, "full_name": request.creator.full_name, "annual_usage": annual_usage, "edit_link": edit_link, diff --git a/atst/utils.py b/atst/utils.py index f836cea2..db4933f4 100644 --- a/atst/utils.py +++ b/atst/utils.py @@ -1,2 +1,2 @@ def first_or_none(predicate, lst): - return next((x for x in lst if predicate(x)), None,) + return next((x for x in lst if predicate(x)), None) diff --git a/templates/requests.html b/templates/requests.html index edb6f7d8..b95bd050 100644 --- a/templates/requests.html +++ b/templates/requests.html @@ -94,7 +94,7 @@ JEDI Cloud Request ID - Date Request Initiated / Created + Date Request Submitted {% if extended_view %} Requester Reason Flagged @@ -110,7 +110,7 @@ {{ r['order_id'] }} {% if r['is_new'] %}New{% endif %} - {{ r['date'] }} + {{ r.last_submission_timestamp }} {% if extended_view %} {{ r['full_name'] }} From acc9f21e7829bbe7e3a91fa1e96e21f08851317b Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 4 Sep 2018 13:20:37 -0400 Subject: [PATCH 5/5] Fix date format --- atst/routes/requests/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atst/routes/requests/index.py b/atst/routes/requests/index.py index c9b15705..6a5cc0f4 100644 --- a/atst/routes/requests/index.py +++ b/atst/routes/requests/index.py @@ -12,7 +12,7 @@ def map_request(request): app_count = request.body.get("details_of_use", {}).get("num_software_systems", 0) annual_usage = request.annual_spend last_submission_timestamp = ( - request.last_submission_timestamp.format("M/DD/YYY") + request.last_submission_timestamp.format("M/DD/YYYY") if request.last_submission_timestamp else "-" )