Handle request status event transitions
This commit is contained in:
parent
f3be2d76ea
commit
85034185bc
@ -6,9 +6,11 @@ from atst.models.request_status_event import RequestStatusEvent, RequestStatus
|
|||||||
from atst.models.request_review import RequestReview
|
from atst.models.request_review import RequestReview
|
||||||
from atst.models.request_internal_comment import RequestInternalComment
|
from atst.models.request_internal_comment import RequestInternalComment
|
||||||
from atst.utils import deep_merge
|
from atst.utils import deep_merge
|
||||||
|
from atst.queue import queue
|
||||||
|
|
||||||
from .query import RequestsQuery
|
from .query import RequestsQuery
|
||||||
from .authorization import RequestsAuthorization
|
from .authorization import RequestsAuthorization
|
||||||
|
from .status_event_handler import RequestStatusEventHandler
|
||||||
|
|
||||||
|
|
||||||
def create_revision_from_request_body(body):
|
def create_revision_from_request_body(body):
|
||||||
@ -95,11 +97,17 @@ class Requests(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_status(cls, request, status: RequestStatus):
|
def set_status(cls, request, status: RequestStatus):
|
||||||
|
old_status = request.status
|
||||||
status_event = RequestStatusEvent(
|
status_event = RequestStatusEvent(
|
||||||
new_status=status, revision=request.latest_revision
|
new_status=status, revision=request.latest_revision
|
||||||
)
|
)
|
||||||
request.status_events.append(status_event)
|
request.status_events.append(status_event)
|
||||||
return RequestsQuery.add_and_commit(request)
|
updated_request = RequestsQuery.add_and_commit(request)
|
||||||
|
RequestStatusEventHandler(queue).handle_status_change(
|
||||||
|
updated_request, old_status, status
|
||||||
|
)
|
||||||
|
|
||||||
|
return updated_request
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def should_auto_approve(cls, request):
|
def should_auto_approve(cls, request):
|
||||||
|
41
atst/domain/requests/status_event_handler.py
Normal file
41
atst/domain/requests/status_event_handler.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
from flask import render_template
|
||||||
|
|
||||||
|
from atst.models.request_status_event import RequestStatus
|
||||||
|
|
||||||
|
|
||||||
|
class RequestStatusEventHandler(object):
|
||||||
|
def __init__(self, queue):
|
||||||
|
self.queue = queue
|
||||||
|
|
||||||
|
def handle_status_change(self, request, old_status, new_status):
|
||||||
|
handler = self._get_handler(old_status, new_status)
|
||||||
|
if handler:
|
||||||
|
handler(request)
|
||||||
|
|
||||||
|
def _get_handler(self, old_status, new_status):
|
||||||
|
return {
|
||||||
|
(
|
||||||
|
RequestStatus.PENDING_CCPO_ACCEPTANCE,
|
||||||
|
RequestStatus.PENDING_FINANCIAL_VERIFICATION,
|
||||||
|
): self._send_email,
|
||||||
|
(
|
||||||
|
RequestStatus.PENDING_CCPO_ACCEPTANCE,
|
||||||
|
RequestStatus.CHANGES_REQUESTED,
|
||||||
|
): self._send_email,
|
||||||
|
(
|
||||||
|
RequestStatus.PENDING_CCPO_APPROVAL,
|
||||||
|
RequestStatus.CHANGES_REQUESTED_TO_FINVER,
|
||||||
|
): self._send_email,
|
||||||
|
(
|
||||||
|
RequestStatus.PENDING_CCPO_APPROVAL,
|
||||||
|
RequestStatus.APPROVED,
|
||||||
|
): self._send_email,
|
||||||
|
}.get((old_status, new_status))
|
||||||
|
|
||||||
|
def _send_email(self, request):
|
||||||
|
email_body = render_template(
|
||||||
|
"emails/request_status_change.txt", request=request
|
||||||
|
)
|
||||||
|
self.queue.send_mail(
|
||||||
|
[request.creator.email], "Your JEDI request status has changed", email_body
|
||||||
|
)
|
@ -27,8 +27,8 @@ class ATSTQueue(RQ):
|
|||||||
# pylint: disable=pointless-string-statement
|
# pylint: disable=pointless-string-statement
|
||||||
"""Instance methods to queue up application-specific jobs."""
|
"""Instance methods to queue up application-specific jobs."""
|
||||||
|
|
||||||
def send_mail(self, to, subject, body):
|
def send_mail(self, recipients, subject, body):
|
||||||
self._queue_job(ATSTQueue._send_mail, to, subject, body)
|
self._queue_job(ATSTQueue._send_mail, recipients, subject, body)
|
||||||
|
|
||||||
# pylint: disable=pointless-string-statement
|
# pylint: disable=pointless-string-statement
|
||||||
"""Class methods to actually perform the work.
|
"""Class methods to actually perform the work.
|
||||||
@ -38,8 +38,8 @@ class ATSTQueue(RQ):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _send_mail(self, to, subject, body):
|
def _send_mail(self, recipients, subject, body):
|
||||||
app.mailer.send(to, subject, body)
|
app.mailer.send(recipients, subject, body)
|
||||||
|
|
||||||
|
|
||||||
queue = ATSTQueue()
|
queue = ATSTQueue()
|
||||||
|
5
templates/emails/request_status_change.txt
Normal file
5
templates/emails/request_status_change.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<h1>Your JEDI request status has changed</h1>
|
||||||
|
|
||||||
|
The status of your JEDI Cloud request - {{ request.name }} - was recently updated. Log in to see whether this change requires an action or response from you.
|
||||||
|
|
||||||
|
{{ url_for('requests.view_request_details', request_id=request.id, _external=True) }}
|
@ -137,8 +137,7 @@ def extended_financial_verification_data(pdf_upload):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function", autouse=True)
|
||||||
def queue():
|
def queue():
|
||||||
_queue = atst_queue
|
yield atst_queue
|
||||||
yield _queue
|
atst_queue.get_queue().empty()
|
||||||
_queue.get_queue().empty()
|
|
||||||
|
@ -6,13 +6,11 @@ from atst.domain.requests import Requests
|
|||||||
from atst.domain.requests.authorization import RequestsAuthorization
|
from atst.domain.requests.authorization import RequestsAuthorization
|
||||||
from atst.models.request import Request
|
from atst.models.request import Request
|
||||||
from atst.models.request_status_event import RequestStatus
|
from atst.models.request_status_event import RequestStatus
|
||||||
from atst.models.task_order import Source as TaskOrderSource
|
|
||||||
|
|
||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
RequestFactory,
|
RequestFactory,
|
||||||
UserFactory,
|
UserFactory,
|
||||||
RequestStatusEventFactory,
|
RequestStatusEventFactory,
|
||||||
TaskOrderFactory,
|
|
||||||
RequestRevisionFactory,
|
RequestRevisionFactory,
|
||||||
RequestReviewFactory,
|
RequestReviewFactory,
|
||||||
)
|
)
|
||||||
@ -222,3 +220,37 @@ def test_random_user_cannot_view_request():
|
|||||||
request = RequestFactory.create()
|
request = RequestFactory.create()
|
||||||
|
|
||||||
assert not RequestsAuthorization(user, request).can_view
|
assert not RequestsAuthorization(user, request).can_view
|
||||||
|
|
||||||
|
|
||||||
|
def test_pending_finver_triggers_notification(queue):
|
||||||
|
request = RequestFactory.create()
|
||||||
|
request = Requests.set_status(request, RequestStatus.PENDING_CCPO_ACCEPTANCE)
|
||||||
|
request = Requests.set_status(request, RequestStatus.PENDING_FINANCIAL_VERIFICATION)
|
||||||
|
assert len(queue.get_queue()) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_changes_requested_triggers_notification(queue):
|
||||||
|
request = RequestFactory.create()
|
||||||
|
request = Requests.set_status(request, RequestStatus.PENDING_CCPO_ACCEPTANCE)
|
||||||
|
request = Requests.set_status(request, RequestStatus.CHANGES_REQUESTED)
|
||||||
|
assert len(queue.get_queue()) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_changes_requested_to_finver_triggers_notification(queue):
|
||||||
|
request = RequestFactory.create()
|
||||||
|
request = Requests.set_status(request, RequestStatus.PENDING_CCPO_APPROVAL)
|
||||||
|
request = Requests.set_status(request, RequestStatus.CHANGES_REQUESTED_TO_FINVER)
|
||||||
|
assert len(queue.get_queue()) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_approval_triggers_notification(queue):
|
||||||
|
request = RequestFactory.create()
|
||||||
|
request = Requests.set_status(request, RequestStatus.PENDING_CCPO_APPROVAL)
|
||||||
|
request = Requests.set_status(request, RequestStatus.APPROVED)
|
||||||
|
assert len(queue.get_queue()) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_submitted_does_not_trigger_notification(queue):
|
||||||
|
request = RequestFactory.create()
|
||||||
|
request = Requests.set_status(request, RequestStatus.SUBMITTED)
|
||||||
|
assert len(queue.get_queue()) == 0
|
||||||
|
@ -239,7 +239,9 @@ def test_displays_ccpo_review_comment(user_session, client):
|
|||||||
request = RequestFactory.create(creator=creator)
|
request = RequestFactory.create(creator=creator)
|
||||||
request = Requests.set_status(request, RequestStatus.CHANGES_REQUESTED)
|
request = Requests.set_status(request, RequestStatus.CHANGES_REQUESTED)
|
||||||
review_comment = "add all of the correct info, instead of the incorrect info"
|
review_comment = "add all of the correct info, instead of the incorrect info"
|
||||||
RequestReviewFactory.create(reviewer=ccpo, comment=review_comment, status=request.status_events[-1])
|
RequestReviewFactory.create(
|
||||||
|
reviewer=ccpo, comment=review_comment, status=request.status_events[-1]
|
||||||
|
)
|
||||||
response = client.get("/requests/new/1/{}".format(request.id))
|
response = client.get("/requests/new/1/{}".format(request.id))
|
||||||
body = response.data.decode()
|
body = response.data.decode()
|
||||||
assert review_comment in body
|
assert review_comment in body
|
||||||
|
Loading…
x
Reference in New Issue
Block a user