🔍 Code Extractor

function remove_approver_from_active_approval_v1

Maturity: 66

Removes an approver from an active approval cycle with permission checks, audit logging, and notifications.

File:
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
Lines:
1294 - 1400
Complexity:
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

  • CDocs
  • typing
  • datetime
  • logging
  • traceback

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

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function remove_approver_from_active_approval 95.2% similar

    Removes an approver from an active approval cycle with permission checks, validation, and notification handling.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function add_approver_to_active_approval_v1 79.3% similar

    Adds a new approver to an active approval cycle with permission checks, validation, audit logging, and email notifications.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
  • function cancel_approval_cycle_v1 78.1% similar

    Cancels an active approval cycle, reverting the associated document to draft status, logging the cancellation, and notifying all pending approvers.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
  • function cancel_approval_cycle 75.1% similar

    Cancels an active approval cycle for a controlled document, updating the approval status, notifying approvers, and reverting the document to DRAFT status if no other active approvals exist.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function remove_reviewer_from_active_review 73.6% similar

    Removes a reviewer from an active review cycle, updating assignment status, adjusting sequential review orders if needed, logging the event, and notifying the removed reviewer.

    From: /tf/active/vicechatdev/CDocs/controllers/review_controller.py
← Back to Browse