function remove_approver_from_active_approval_v1
Removes an approver from an active approval cycle with permission checks, audit logging, and notifications.
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
1294 - 1400
complex
Purpose
This function manages the removal of an approver from an ongoing document approval process. It validates permissions (either the initiator or users with MANAGE_APPROVALS permission can remove approvers), ensures the approval cycle is still active, prevents removal of approvers who have already completed their approval, logs the action in the audit trail, and sends notifications to the removed approver. This is typically used when an approver needs to be replaced or is no longer required in the approval workflow.
Source Code
def remove_approver_from_active_approval(
user: DocUser,
approval_uid: str,
approver_uid: str,
reason: str
) -> Dict[str, Any]:
"""
Remove an approver from an active approval cycle.
Args:
user: The user removing the approver
approval_uid: UID of the approval cycle
approver_uid: UID of the approver to remove
reason: Reason for removal
Returns:
Dictionary with success flag and status
"""
try:
# Get approval cycle
approval_cycle = ApprovalCycle(uid=approval_uid)
if not approval_cycle:
raise ResourceNotFoundError("Approval cycle not found")
# Check if user has permission
is_initiator = approval_cycle._data.get('initiatedByUID') == user.uid
has_permission = permissions.user_has_permission(user, "MANAGE_APPROVALS")
if not (is_initiator or has_permission):
raise PermissionError("You do not have permission to remove approvers")
# Check if approval is still active
if not approval_cycle.is_active:
raise BusinessRuleError(f"Cannot remove approver from a {approval_cycle.status} approval cycle")
# Check if actually an approver
approver = DocUser(uid=approver_uid)
if not approval_cycle.is_approver(approver_uid):
raise ValidationError(f"{approver.name if approver else 'User'} is not an approver for this document")
# Get assignment
assignment = approval_cycle.get_approver_assignment(approver_uid)
if not assignment:
raise ResourceNotFoundError("Approver assignment not found")
# Can't remove if already completed
if assignment.status == 'COMPLETED':
raise BusinessRuleError("Cannot remove an approver who has already completed their approval")
# Remove approver
assignment.removal_date = datetime.now()
assignment.removal_reason = reason
# Create audit trail entry
document_uid = approval_cycle.document_uid
if document_uid:
audit_trail.log_event(
user=user,
resource_uid=document_uid,
resource_type='ApprovalCycle',
event_type="APPROVER_REMOVED",
description=f"Removed {approver.name if approver else 'unknown user'} as approver",
details={
"approval_cycle_uid": approval_uid,
"approver_uid": approver_uid,
"approver_name": approver.name if approver else 'Unknown',
"reason": reason
}
)
# Send notification to removed approver
if approver:
from CDocs.controllers.document_controller import get_document
document = get_document(document_uid=document_uid)
if document:
notifications.send_notification(
notification_type="APPROVAL_REMOVED",
users=approver.uid,
resource_uid=approval_uid,
resource_type="ApprovalCycle",
message=f"You have been removed from the approval process for {document.get('title')}",
details={
"document_uid": document_uid,
"document_number": document.get("docNumber"),
"document_title": document.get("title"),
"approval_cycle_uid": approval_uid,
"reason": reason
},
send_email=True,
email_template="approval_removed"
)
return {
"success": True,
"message": f"Approver removed from approval cycle",
"approver_uid": approver_uid
}
except (ResourceNotFoundError, PermissionError, BusinessRuleError, ValidationError) as e:
logger.warning(f"Error removing approver: {e}")
return {"success": False, "message": str(e)}
except Exception as e:
logger.error(f"Unexpected error removing approver: {e}")
import traceback
logger.error(traceback.format_exc())
return {"success": False, "message": "An unexpected error occurred"}
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
user |
DocUser | - | positional_or_keyword |
approval_uid |
str | - | positional_or_keyword |
approver_uid |
str | - | positional_or_keyword |
reason |
str | - | positional_or_keyword |
Parameter Details
user: DocUser object representing the user performing the removal action. Must be either the approval cycle initiator or have MANAGE_APPROVALS permission.
approval_uid: String UID (unique identifier) of the approval cycle from which the approver should be removed. Must reference an existing, active approval cycle.
approver_uid: String UID of the approver to be removed from the approval cycle. Must be a current approver who has not yet completed their approval.
reason: String explaining why the approver is being removed. This is logged in the audit trail and sent to the removed approver in the notification.
Return Value
Type: Dict[str, Any]
Returns a dictionary with keys: 'success' (boolean indicating if removal succeeded), 'message' (string describing the outcome or error), and optionally 'approver_uid' (string UID of the removed approver on success). On failure, only 'success' (False) and 'message' (error description) are returned.
Dependencies
CDocstypingdatetimeloggingtraceback
Required Imports
from typing import Dict, Any
from datetime import datetime
import logging
from CDocs.models.user_extensions import DocUser
from CDocs.models.approval import ApprovalCycle, ApproverAssignment
from CDocs.config import permissions
from CDocs.utils import audit_trail, notifications
from CDocs.controllers import ResourceNotFoundError, PermissionError, BusinessRuleError, ValidationError, log_controller_action
import traceback
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.controllers.document_controller import get_document
Condition: only when document_uid exists and notifications need to be sent with document details
Required (conditional)Usage Example
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.approval_controller import remove_approver_from_active_approval
# Get the user performing the action
removing_user = DocUser(uid='user123')
# Remove an approver from an approval cycle
result = remove_approver_from_active_approval(
user=removing_user,
approval_uid='approval_cycle_456',
approver_uid='approver_789',
reason='Approver is on extended leave and needs to be replaced'
)
if result['success']:
print(f"Successfully removed approver: {result['message']}")
print(f"Removed approver UID: {result['approver_uid']}")
else:
print(f"Failed to remove approver: {result['message']}")
Best Practices
- Always provide a meaningful reason for removal as it will be logged and sent to the removed approver
- Ensure the calling user has appropriate permissions before invoking this function
- Handle the returned dictionary to check the 'success' flag before proceeding with dependent operations
- This function should only be called on active approval cycles; attempting to remove approvers from completed or cancelled cycles will fail
- Cannot remove approvers who have already completed their approval - check assignment status before attempting removal
- The function is decorated with @log_controller_action which provides automatic logging of the action
- All exceptions are caught and converted to error responses, so check the 'success' flag rather than catching exceptions
- The function sends email notifications automatically, ensure email system is properly configured
- Audit trail entries are created automatically for compliance and tracking purposes
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function remove_approver_from_active_approval 95.2% similar
-
function add_approver_to_active_approval_v1 79.3% similar
-
function cancel_approval_cycle_v1 78.1% similar
-
function cancel_approval_cycle 75.1% similar
-
function remove_reviewer_from_active_review 73.6% similar