function close_approval_cycle_v1
Administratively closes an approval cycle by setting a final decision (APPROVED or REJECTED), updating the associated document status, and notifying relevant stakeholders.
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
796 - 943
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
typingdatetimeloggingtracebackCDocs.dbCDocs.configCDocs.models.documentCDocs.models.approvalCDocs.models.user_extensionsCDocs.utilsCDocs.controllersCDocs.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)
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function close_approval_cycle 88.4% similar
-
function complete_approval_v1 80.4% similar
-
function complete_approval 80.4% similar
-
function cancel_approval_cycle_v1 77.9% similar
-
function close_review_cycle 77.1% similar