🔍 Code Extractor

function add_approver_to_active_approval_v1

Maturity: 72

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

File:
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
Lines:
1183 - 1291
Complexity:
complex

Purpose

This function manages the addition of approvers to ongoing document approval cycles. It validates permissions (either the initiator or users with MANAGE_APPROVALS permission), ensures the approval cycle is still active, verifies the new approver exists and isn't already assigned, adds them to the cycle with optional instructions and sequence order, logs the action in the audit trail, and sends email notifications to the newly assigned approver. It's designed for document management systems where approval workflows can be modified dynamically.

Source Code

def add_approver_to_active_approval(
    user: DocUser,
    approval_uid: str,
    approver_uid: str,
    instructions: Optional[str] = None,
    sequence_order: Optional[int] = None
) -> Dict[str, Any]:
    """
    Add a new approver to an active approval cycle.
    
    Args:
        user: The user adding the approver
        approval_uid: UID of the approval cycle
        approver_uid: UID of the user to add as approver
        instructions: Instructions for the new approver
        sequence_order: Sequence order for the new approver
        
    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 add approvers")
            
        # Check if approval is still active
        if not approval_cycle.is_active:
            raise BusinessRuleError(f"Cannot add approver to a {approval_cycle.status} approval cycle")
            
        # Verify approver exists
        approver = DocUser(uid=approver_uid)
        if not approver or not approver.uid:
            raise ValidationError(f"Invalid approver UID: {approver_uid}")
            
        # Check if already an approver
        if approval_cycle.is_approver(approver_uid):
            raise BusinessRuleError(f"{approver.name} is already an approver for this document")
            
        # Add approver
        success = approval_cycle.add_approver(approver_uid, instructions=instructions)
        
        if not success:
            raise BusinessRuleError(f"Failed to add {approver.name} as approver")
            
        # Update sequence order if provided and this is a sequential approval
        assignment = approval_cycle.get_approver_assignment(approver_uid)
        if assignment and sequence_order is not None and approval_cycle._data.get('sequential', False):
            assignment.sequence_order = sequence_order
        
        # 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_ADDED",
                details={
                    "approval_cycle_uid": approval_uid,
                    "approver_uid": approver_uid,
                    "approver_name": approver.name,
                    "sequence_order": sequence_order
                }
            )
            
            # Send notification to new approver
            from CDocs.controllers.document_controller import get_document
            document = get_document(document_uid=document_uid)
            if document:
                notifications.send_notification(
                    notification_type="APPROVAL_ASSIGNED",
                    users=approver.uid,
                    resource_uid=approval_uid,
                    resource_type="ApprovalCycle",
                    message=f"You have been assigned to approve {document.get('title')}",
                    details={
                        "document_uid": document_uid,
                        "document_number": document.get("docNumber"),
                        "document_title": document.get("title"),
                        "approval_cycle_uid": approval_uid,
                        "due_date": approval_cycle.due_date.isoformat() if approval_cycle.due_date else None
                    },
                    send_email=True,
                    email_template="approval_assigned"
                )
        
        return {
            "success": True,
            "message": f"{approver.name} added as approver",
            "approver_uid": approver_uid
        }
        
    except (ResourceNotFoundError, PermissionError, BusinessRuleError, ValidationError) as e:
        logger.warning(f"Error adding approver: {e}")
        return {"success": False, "message": str(e)}
        
    except Exception as e:
        logger.error(f"Unexpected error adding 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
instructions Optional[str] None positional_or_keyword
sequence_order Optional[int] None positional_or_keyword

Parameter Details

user: DocUser object representing the authenticated user attempting to add the approver. Must have either initiated the approval cycle or possess MANAGE_APPROVALS permission.

approval_uid: String unique identifier (UID) of the approval cycle to which the approver will be added. Must reference an existing, active approval cycle.

approver_uid: String unique identifier (UID) of the user to be added as an approver. Must reference a valid DocUser who is not already an approver on this cycle.

instructions: Optional string containing specific instructions or guidance for the new approver about what to review or consider during approval. Defaults to None.

sequence_order: Optional integer specifying the position of this approver in sequential approval workflows. Only relevant if the approval cycle is configured as sequential. Defaults to None.

Return Value

Type: Dict[str, Any]

Returns a dictionary with keys: 'success' (boolean indicating operation success), 'message' (string describing the outcome or error), and 'approver_uid' (string UID of the added approver, only present on success). On failure, only 'success' and 'message' are returned.

Dependencies

  • CDocs
  • typing
  • datetime
  • logging
  • traceback

Required Imports

from typing import Dict, Any, Optional
from CDocs.models.user_extensions import DocUser
from CDocs.models.approval import ApprovalCycle
from CDocs.config import permissions
from CDocs.utils import audit_trail, notifications
from CDocs.controllers import log_controller_action, ResourceNotFoundError, PermissionError, BusinessRuleError, ValidationError
import logging

Conditional/Optional Imports

These imports are only needed under specific conditions:

from CDocs.controllers.document_controller import get_document

Condition: imported inside the function when document details are needed for notification purposes after successfully adding an approver

Required (conditional)
import traceback

Condition: imported inside exception handler for detailed error logging when unexpected exceptions occur

Required (conditional)

Usage Example

from CDocs.models.user_extensions import DocUser
from your_module import add_approver_to_active_approval

# Get the current user and approver
current_user = DocUser(uid='user123')
new_approver_uid = 'approver456'

# Add approver to an active approval cycle
result = add_approver_to_active_approval(
    user=current_user,
    approval_uid='approval789',
    approver_uid=new_approver_uid,
    instructions='Please review the technical specifications in section 3',
    sequence_order=2
)

if result['success']:
    print(f"Successfully added approver: {result['message']}")
    print(f"Approver UID: {result['approver_uid']}")
else:
    print(f"Failed to add approver: {result['message']}")

Best Practices

  • Always check the returned 'success' flag before proceeding with dependent operations
  • Ensure the user object passed has been properly authenticated before calling this function
  • The function handles its own exception catching and returns structured error messages rather than raising exceptions
  • For sequential approvals, provide sequence_order to maintain proper approval flow
  • The function automatically sends email notifications; ensure email service is properly configured
  • Audit trail entries are created automatically for compliance tracking
  • The decorator log_controller_action should be present on the function for proper action logging
  • This function modifies active approval cycles; ensure proper transaction handling in the calling context
  • The function validates that the approval cycle is active before allowing modifications
  • Permission checks are performed for both initiators and users with MANAGE_APPROVALS permission

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function add_approver_to_active_approval 92.1% similar

    Adds a new approver to an active approval cycle for a controlled document, with optional sequence ordering and custom instructions.

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

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

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
  • function create_approval_cycle 77.7% similar

    Creates a new approval cycle for a document, assigning approvers with configurable workflow options (sequential/parallel), instructions, and due dates.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
  • function remove_approver_from_active_approval 75.5% 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 complete_approval_v1 74.3% similar

    Records a user's approval decision (APPROVED or REJECTED) for a document in an approval cycle, updating the approval status and document state accordingly.

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