Adding some additional logic to the approval endpoint so that we take related approvals into account when setting the status. In addtion to prevous status options, there is a new status of "AWAITING" which means there are pending approvals before this approval that still need to be approved or canceled.

This commit is contained in:
Dan Funk 2020-06-05 14:33:00 -04:00
parent b6abb0cbe2
commit f0db5b70fc
5 changed files with 39 additions and 3 deletions

View File

@ -814,6 +814,12 @@ paths:
description: If set to true, returns all the approvals known to the system. description: If set to true, returns all the approvals known to the system.
schema: schema:
type: boolean type: boolean
- name: as_user
in: query
required: false
description: If provided, returns the approval results as they would appear for that user.
schema:
type: string
get: get:
operationId: crc.api.approval.get_approvals operationId: crc.api.approval.get_approvals
summary: Provides a list of workflows approvals summary: Provides a list of workflows approvals

View File

@ -13,9 +13,11 @@ from crc.services.approval_service import ApprovalService
from crc.services.ldap_service import LdapService from crc.services.ldap_service import LdapService
def get_approvals(everything=False): def get_approvals(everything=False, as_user=None):
if everything: if everything:
approvals = ApprovalService.get_all_approvals(include_cancelled=True) approvals = ApprovalService.get_all_approvals(include_cancelled=True)
elif as_user:
approvals = ApprovalService.get_all_approvals(as_user, include_cancelled=False)
else: else:
approvals = ApprovalService.get_approvals_per_user(g.user.uid, include_cancelled=False) approvals = ApprovalService.get_approvals_per_user(g.user.uid, include_cancelled=False)
results = ApprovalSchema(many=True).dump(approvals) results = ApprovalSchema(many=True).dump(approvals)

View File

@ -20,6 +20,9 @@ class ApprovalStatus(enum.Enum):
DECLINED = "DECLINED" # rejected by the reviewer DECLINED = "DECLINED" # rejected by the reviewer
CANCELED = "CANCELED" # The document was replaced with a new version and this review is no longer needed. CANCELED = "CANCELED" # The document was replaced with a new version and this review is no longer needed.
# Used for overall status only, never set on a task.
AWAITING = "AWAITING" # awaiting another approval
class ApprovalFile(db.Model): class ApprovalFile(db.Model):
file_data_id = db.Column(db.Integer, db.ForeignKey(FileDataModel.id), primary_key=True) file_data_id = db.Column(db.Integer, db.ForeignKey(FileDataModel.id), primary_key=True)

View File

@ -11,7 +11,8 @@ class RequestApproval(Script):
return """ return """
Creates an approval request on this workflow, by the given approver_uid(s)," Creates an approval request on this workflow, by the given approver_uid(s),"
Takes multiple arguments, which should point to data located in current task Takes multiple arguments, which should point to data located in current task
or be quoted strings. or be quoted strings. The order is important. Approvals will be processed
in this order.
Example: Example:
RequestApproval approver1 "dhf8r" RequestApproval approver1 "dhf8r"

View File

@ -27,19 +27,43 @@ class ApprovalService(object):
if not include_cancelled: if not include_cancelled:
query=query.filter(ApprovalModel.status != ApprovalStatus.CANCELED.value) query=query.filter(ApprovalModel.status != ApprovalStatus.CANCELED.value)
approvals = query.all() approvals = query.all() ## all non-cancelled approvals.
study_approval_status = ""
# IF THIS IS RELATED TO THE CURRENT USER
for approval_model in approvals: for approval_model in approvals:
if approval_model.approver_uid == approver_uid: if approval_model.approver_uid == approver_uid:
main_approval = Approval.from_model(approval_model) main_approval = Approval.from_model(approval_model)
else: else:
related_approvals.append(Approval.from_model(approval_model)) related_approvals.append(Approval.from_model(approval_model))
# IF WE ARE JUST RETURNING ALL OF THE APPROVALS PER STUDY
if not main_approval and len(related_approvals) > 0: if not main_approval and len(related_approvals) > 0:
main_approval = related_approvals[0] main_approval = related_approvals[0]
related_approvals = related_approvals[1:] related_approvals = related_approvals[1:]
if(main_approval): # May be null if the study has no approvals.
main_approval.status = ApprovalService.__calculate_overall_approval_status(main_approval)
if len(related_approvals) > 0: if len(related_approvals) > 0:
main_approval.related_approvals = related_approvals main_approval.related_approvals = related_approvals
return main_approval return main_approval
@staticmethod
def __calculate_overall_approval_status(approval):
# In the case of pending approvals, check to see if there is a related approval
# that proceeds this approval - and if it is declined, or still pending, then change
# the state of the approval to be Delcined, or Waiting respectively.
if approval.status == ApprovalStatus.PENDING.value:
for ra in approval.related_approvals:
if ra.id < approval.id:
if ra.status == ApprovalStatus.DECLINED.value or ra.status == ApprovalStatus.CANCELED.value:
return ra.status # If any prior approval id declined or cancelled so is this approval.
elif ra.status == ApprovalStatus.PENDING.value:
return ApprovalStatus.AWAITING.value # if any prior approval is pending, then this is waiting.
else:
return approval.status
@staticmethod @staticmethod
def get_approvals_per_user(approver_uid, include_cancelled=False): def get_approvals_per_user(approver_uid, include_cancelled=False):
"""Returns a list of approval objects (not db models) for the given """Returns a list of approval objects (not db models) for the given