function cancel_approval_cycle_v1
Cancels an active approval cycle, reverting the associated document to draft status, logging the cancellation, and notifying all pending approvers.
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
946 - 1070
complex
Purpose
This function handles the complete workflow for canceling an approval cycle in a document management system. It validates user permissions (either the initiator or users with MANAGE_APPROVALS permission), ensures the approval cycle is active, updates the approval cycle status to CANCELLED, resets the document to DRAFT status, adds a cancellation comment, creates an audit trail entry, and sends email notifications to all pending approvers. The operation is wrapped in a database transaction to ensure data consistency.
Source Code
def cancel_approval_cycle(
user: DocUser,
approval_uid: str,
reason: str
) -> Dict[str, Any]:
"""
Cancel an active approval cycle.
Args:
user: The user cancelling the approval
approval_uid: UID of the approval cycle
reason: Reason for cancellation
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 to cancel
is_initiator = (
approval_cycle._data.get('initiatedByUID') == user.uid or
permissions.user_has_permission(user, "MANAGE_APPROVALS")
)
if not is_initiator:
raise PermissionError("You do not have permission to cancel this approval cycle")
# Check if approval is still active
if not approval_cycle.is_active:
raise BusinessRuleError(f"This approval cycle is already {approval_cycle.status}")
document_uid = approval_cycle.document_uid
# Using the proper transaction handling
from CDocs.db import get_driver
driver = get_driver()
with driver.session() as session:
with session.begin_transaction() as tx:
try:
# Update approval cycle status
approval_cycle.status = 'CANCELLED'
approval_cycle.completion_date = datetime.now()
# Add comment with cancellation reason
approval_cycle.add_comment(
commenter=user,
text=f"Approval cycle cancelled: {reason}",
properties={"comment_type": "CANCELLATION"}
)
# Update document status back to state before approval
if document_uid:
from CDocs.controllers.document_controller import update_document
update_document(
document_uid=document_uid,
user=user,
status="DRAFT" # Reset to draft state
)
# 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 cancelling approval cycle: {e}")
raise BusinessRuleError(f"Failed to cancel approval cycle: {e}")
# Create audit trail entry outside transaction
if document_uid:
audit_trail.log_event(
event_type="APPROVAL_CYCLE_CANCELLED",
user=user,
resource_uid=approval_uid,
resource_type="ApprovalCycle",
details={
"document_uid": document_uid,
"reason": reason
}
)
# Send notifications to approvers
from CDocs.controllers.document_controller import get_document
document = get_document(document_uid=document_uid)
if document:
for assignment in approval_cycle.get_approver_assignments():
if assignment.status == 'PENDING':
approver = DocUser(uid=assignment.approver_uid)
if approver:
notifications.send_notification(
notification_type="APPROVAL_CYCLE_CANCELLED",
users=approver.uid,
resource_uid=approval_uid,
resource_type="ApprovalCycle",
message=f"The approval cycle for {document.get('docNumber')} has been cancelled",
details={
"document_uid": document_uid,
"document_number": document.get("docNumber"),
"document_title": document.get("title"),
"cancelled_by": user.name,
"approval_cycle_uid": approval_uid,
"reason": reason
},
send_email=True,
email_template="approval_cancelled"
)
return {
"success": True,
"message": "Approval cycle cancelled",
"status": "CANCELLED"
}
except (ResourceNotFoundError, PermissionError, BusinessRuleError) as e:
logger.warning(f"Error cancelling approval cycle: {e}")
return {"success": False, "message": str(e)}
except Exception as e:
logger.error(f"Unexpected error cancelling 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 |
reason |
str | - | positional_or_keyword |
Parameter Details
user: A DocUser object representing the user attempting to cancel the approval cycle. Must be either the initiator of the approval cycle or have MANAGE_APPROVALS permission. Used for permission checks, audit logging, and notification attribution.
approval_uid: A string containing the unique identifier (UID) of the approval cycle to be cancelled. Must correspond to an existing ApprovalCycle record in the database.
reason: A string explaining why the approval cycle is being cancelled. This reason is recorded in the approval cycle comments, audit trail, and sent to approvers in notification emails. Should be descriptive and meaningful for audit purposes.
Return Value
Type: Dict[str, Any]
Returns a dictionary with keys: 'success' (boolean indicating if cancellation succeeded), 'message' (string with human-readable status or error message), and 'status' (string with value 'CANCELLED' on success). On failure, returns success=False with an appropriate error message describing what went wrong (e.g., permission denied, resource not found, business rule violation).
Dependencies
CDocs.models.documentCDocs.models.approvalCDocs.models.user_extensionsCDocs.utils.audit_trailCDocs.utils.notificationsCDocs.controllersCDocs.controllers.document_controllerCDocs.dbCDocs.config.settingsCDocs.config.permissions
Required Imports
from typing import Dict, Any
from datetime import datetime
import logging
from CDocs.models.approval import ApprovalCycle
from CDocs.models.user_extensions import DocUser
from CDocs.config import permissions
from CDocs.utils import audit_trail, notifications
from CDocs.controllers import log_controller_action, PermissionError, ResourceNotFoundError, BusinessRuleError
from CDocs.db import get_driver
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.controllers.document_controller import update_document
Condition: imported inside transaction block when document_uid exists to update document status
Required (conditional)from CDocs.controllers.document_controller import get_document
Condition: imported after transaction to retrieve document details for notifications
Required (conditional)import traceback
Condition: imported in exception handling blocks for detailed error logging
Required (conditional)Usage Example
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.approval_controller import cancel_approval_cycle
# Get the user performing the cancellation
current_user = DocUser(uid='user_123')
# Cancel an approval cycle
result = cancel_approval_cycle(
user=current_user,
approval_uid='approval_456',
reason='Requirements changed, need to revise document before approval'
)
if result['success']:
print(f"Approval cycle cancelled: {result['message']}")
print(f"Status: {result['status']}")
else:
print(f"Failed to cancel: {result['message']}")
Best Practices
- Always provide a meaningful reason for cancellation as it will be logged in audit trails and sent to approvers
- Ensure the user has appropriate permissions (either initiator or MANAGE_APPROVALS) before calling this function
- The function handles its own transaction management - do not wrap it in another transaction
- Check the 'success' field in the returned dictionary before assuming the operation succeeded
- The function is decorated with @log_controller_action('cancel_approval_cycle') for automatic action logging
- All database operations are wrapped in a transaction that will rollback on any error
- Notifications are sent outside the transaction to avoid blocking the database commit
- The function resets documents to DRAFT status - ensure this aligns with your workflow requirements
- Error handling distinguishes between expected errors (ResourceNotFoundError, PermissionError, BusinessRuleError) and unexpected errors for appropriate logging levels
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function cancel_approval_cycle 93.6% similar
-
function cancel_review_cycle 79.5% similar
-
function remove_approver_from_active_approval_v1 78.1% similar
-
function close_approval_cycle_v1 77.9% similar
-
function remove_approver_from_active_approval 74.9% similar