🔍 Code Extractor

function close_approval_cycle_v1

Maturity: 68

Administratively closes an approval cycle by setting a final decision (APPROVED or REJECTED), updating the associated document status, and notifying relevant stakeholders.

File:
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
Lines:
796 - 943
Complexity:
complex

Purpose

This function provides administrative control to forcibly close an approval cycle that may be stuck or requires manual intervention. It verifies user permissions, validates the approval cycle state, updates the document status accordingly, creates an audit trail, and sends notifications to the document owner and all approvers. The operation is performed within a database transaction to ensure data consistency.

Source Code

def close_approval_cycle(
    user: DocUser,
    approval_uid: str,
    decision: str,
    comments: Optional[str] = None
) -> Dict[str, Any]:
    """
    Administratively close an approval cycle.
    
    Args:
        user: The user closing the approval cycle
        approval_uid: UID of the approval cycle
        decision: Final decision (APPROVED or REJECTED)
        comments: Optional comments on the decision
        
    Returns:
        Dictionary with success flag and status
    """
    try:
        # Verify user has permission to close approval cycles
        if not permissions.user_has_permission(user, "MANAGE_APPROVALS"):
            raise PermissionError("You do not have permission to close approval cycles")
            
        # Get approval cycle
        approval_cycle = ApprovalCycle(uid=approval_uid)
        if not approval_cycle:
            raise ResourceNotFoundError("Approval cycle not found")
            
        # Check if approval cycle is already complete
        if approval_cycle.is_complete:
            raise BusinessRuleError(f"This approval cycle is already complete with status {approval_cycle.status}")
        
        document_uid = approval_cycle.document_uid
        
        # Close the approval cycle
        from CDocs.db import get_driver
        driver = get_driver()
        with driver.session() as session:
            with session.begin_transaction() as tx:
                try:
                    # Set final decision
                    approved = (decision == "APPROVED")
                    approval_cycle.complete_approval(approved=approved)
                    
                    # Add admin comment if provided
                    if comments:
                        approval_cycle.add_comment(
                            commenter=user,
                            text=f"Administrative decision: {comments}",
                            properties={"comment_type": "ADMIN_DECISION"}
                        )
                        
                    # Update document status
                    if document_uid:
                        new_status = "APPROVED" if approved else "REJECTED"
                        from CDocs.controllers.document_controller import update_document
                        update_document(
                            document_uid=document_uid,
                            user=user,
                            status=new_status
                        )
                    
                    # Commit the transaction if everything succeeds
                    tx.commit()
                except Exception as e:
                    # Roll back the transaction if anything fails
                    tx.rollback()
                    logger.error(f"Error in transaction closing approval cycle: {e}")
                    raise BusinessRuleError(f"Failed to close approval cycle: {e}")
        
        # Create audit trail entry
        if document_uid:
            audit_trail.log_event(
                event_type="APPROVAL_CYCLE_CLOSED",
                user=user,
                resource_uid=approval_uid,
                resource_type="ApprovalCycle",
                details={
                    "document_uid": document_uid,
                    "decision": decision,
                    "has_comments": comments is not None and len(comments) > 0
                }
            )
            
            # Send notifications
            from CDocs.controllers.document_controller import get_document
            document = get_document(document_uid=document_uid)
            if document:
                # Notify document owner
                if document.get("owner_uid"):
                    owner = DocUser(uid=document.get("owner_uid"))
                    if owner:
                        notifications.send_notification(
                            notification_type="APPROVAL_CYCLE_CLOSED",
                            users=owner.uid,
                            resource_uid=approval_uid,
                            resource_type="ApprovalCycle",
                            message=f"An admin has closed the approval cycle with decision: {decision}",
                            details={
                                "document_uid": document_uid,
                                "document_number": document.get("docNumber"),
                                "document_title": document.get("title"),
                                "decision": decision,
                                "approver_name": user.name,
                                "approval_cycle_uid": approval_uid
                            },
                            send_email=True,
                            email_template="approval_closed"
                        )                   
                        
                # Notify all approvers
                for assignment in approval_cycle.get_approver_assignments():
                    approver = DocUser(uid=assignment.approver_uid)
                    if approver:
                        notifications.send_notification(
                            notification_type="APPROVAL_CYCLE_CLOSED",
                            users=approver.uid,
                            resource_uid=approval_uid,
                            resource_type="ApprovalCycle",
                            message=f"An admin has closed the approval cycle with decision: {decision}",
                            details={
                                "document_uid": document_uid,
                                "document_number": document.get("docNumber"),
                                "document_title": document.get("title"),
                                "decision": decision,
                                "admin_name": user.name,
                                "approval_cycle_uid": approval_uid
                            },
                            send_email=True,
                            email_template="approval_closed"
                        )
        
        return {
            "success": True,
            "message": f"Approval cycle closed with decision: {decision}",
            "status": approval_cycle.status,
            "decision": decision
        }
        
    except (ResourceNotFoundError, PermissionError, BusinessRuleError) as e:
        logger.warning(f"Error closing approval cycle: {e}")
        return {"success": False, "message": str(e)}
        
    except Exception as e:
        logger.error(f"Unexpected error closing approval cycle: {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
decision str - positional_or_keyword
comments Optional[str] None positional_or_keyword

Parameter Details

user: A DocUser object representing the administrator closing the approval cycle. Must have 'MANAGE_APPROVALS' permission to execute this action.

approval_uid: String containing the unique identifier (UID) of the approval cycle to be closed. Must reference an existing, incomplete approval cycle.

decision: String indicating the final decision for the approval cycle. Expected values are 'APPROVED' or 'REJECTED'. This determines the final status of both the approval cycle and the associated document.

comments: Optional string containing administrative comments explaining the decision to close the approval cycle. If provided, these comments are added to the approval cycle with a special 'ADMIN_DECISION' type marker.

Return Value

Type: Dict[str, Any]

Returns a dictionary with keys: 'success' (boolean indicating operation success), 'message' (string describing the outcome), 'status' (the final status of the approval cycle), and 'decision' (echoing the decision made). On failure, returns a dictionary with 'success': False and 'message' containing the error description.

Dependencies

  • typing
  • datetime
  • logging
  • traceback
  • CDocs.db
  • CDocs.config
  • CDocs.models.document
  • CDocs.models.approval
  • CDocs.models.user_extensions
  • CDocs.utils
  • CDocs.controllers
  • CDocs.controllers.document_controller

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 PermissionError, ResourceNotFoundError, BusinessRuleError
from CDocs.db import get_driver
import logging

Conditional/Optional Imports

These imports are only needed under specific conditions:

from CDocs.controllers.document_controller import update_document

Condition: imported within the transaction block when updating document status

Required (conditional)
from CDocs.controllers.document_controller import get_document

Condition: imported when retrieving document details for notifications

Required (conditional)
import traceback

Condition: imported for error logging when unexpected exceptions occur

Required (conditional)

Usage Example

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

# Get the admin user
admin_user = DocUser(uid='admin-123')

# Close an approval cycle with approval decision
result = close_approval_cycle(
    user=admin_user,
    approval_uid='approval-cycle-456',
    decision='APPROVED',
    comments='Approved administratively due to urgent business need'
)

if result['success']:
    print(f"Approval cycle closed: {result['message']}")
    print(f"Final status: {result['status']}")
else:
    print(f"Failed to close approval cycle: {result['message']}")

# Close with rejection
result = close_approval_cycle(
    user=admin_user,
    approval_uid='approval-cycle-789',
    decision='REJECTED',
    comments='Document does not meet compliance requirements'
)

Best Practices

  • Ensure the user has 'MANAGE_APPROVALS' permission before calling this function
  • Always provide meaningful comments when administratively closing approval cycles for audit purposes
  • Use 'APPROVED' or 'REJECTED' as decision values (case-sensitive)
  • Handle the returned dictionary to check 'success' flag before proceeding with dependent operations
  • Be aware that this function sends email notifications to document owners and all approvers
  • The function uses database transactions - ensure the database driver supports transactions
  • This is a privileged operation that bypasses normal approval workflow - use judiciously
  • The function logs errors and creates audit trail entries automatically
  • Verify the approval cycle is not already complete before attempting to close it
  • The associated document status will be updated to match the decision (APPROVED/REJECTED)

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function close_approval_cycle 88.4% similar

    Closes a completed approval cycle and optionally updates the associated document's status, with permission checks, audit logging, and notifications.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function complete_approval_v1 80.4% 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
  • function complete_approval 80.4% similar

    Completes an approval cycle by recording a user's approval decision (APPROVED, REJECTED, etc.) and managing the approval workflow, including sequential approver activation and final cycle completion.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function cancel_approval_cycle_v1 77.9% 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 close_review_cycle 77.1% similar

    Closes a completed review cycle for a controlled document, with optional document status update, permission validation, and stakeholder notifications.

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