🔍 Code Extractor

function extend_approval_deadline_v1

Maturity: 66

Extends the deadline of an active approval cycle, validates permissions, logs the change, and notifies pending approvers of the new due date.

File:
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
Lines:
1073 - 1180
Complexity:
complex

Purpose

This function allows authorized users (approval initiators or users with MANAGE_APPROVALS permission) to extend the deadline of an active approval cycle. It validates the new due date, updates the approval cycle, creates an audit trail entry, adds a comment explaining the extension, and sends email notifications to all pending approvers informing them of the deadline change.

Source Code

def extend_approval_deadline(
    user: DocUser,
    approval_uid: str,
    new_due_date: datetime,
    reason: Optional[str] = None
) -> Dict[str, Any]:
    """
    Extend the deadline of an approval cycle.
    
    Args:
        user: The user extending the deadline
        approval_uid: UID of the approval cycle
        new_due_date: New due date for the approval
        reason: Reason for extension
        
    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 extend deadline
        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 extend the approval deadline")
            
        # Check if approval is still active
        if not approval_cycle.is_active:
            raise BusinessRuleError(f"Cannot extend deadline of a completed approval cycle")
            
        # Validate new due date
        if new_due_date <= datetime.now():
            raise ValidationError("New due date must be in the future")
            
        # Set new due date
        old_due_date = approval_cycle.due_date
        approval_cycle.due_date = new_due_date
        
        # Add comment with extension reason
        if reason:
            approval_cycle.add_comment(
                commenter=user,
                text=f"Deadline extended from {old_due_date.strftime('%Y-%m-%d')} to {new_due_date.strftime('%Y-%m-%d')}: {reason}",
                properties={"comment_type": "DEADLINE_EXTENSION"}
            )
        
        # 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="APPROVAL_DEADLINE_EXTENDED",
                details={
                    "approval_cycle_uid": approval_uid,
                    "old_due_date": old_due_date.isoformat() if old_due_date else None,
                    "new_due_date": new_due_date.isoformat(),
                    "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_DEADLINE_EXTENDED",
                                users=approver.uid,
                                resource_uid=approval_uid,
                                resource_type="ApprovalCycle",
                                message=f"The approval deadline for {document.get('docNumber')} has been extended to {new_due_date.strftime('%Y-%m-%d')}",
                                details={
                                    "document_uid": document_uid,
                                    "document_number": document.get("docNumber"),
                                    "document_title": document.get("title"),
                                    "extended_by": user.name,
                                    "approval_cycle_uid": approval_uid,
                                    "new_due_date": new_due_date.isoformat()
                                },
                                send_email=True,
                                email_template="approval_deadline_extended"
                            )
        
        return {
            "success": True,
            "message": "Approval deadline extended",
            "new_due_date": new_due_date
        }
        
    except (ResourceNotFoundError, PermissionError, BusinessRuleError, ValidationError) as e:
        logger.warning(f"Error extending approval deadline: {e}")
        return {"success": False, "message": str(e)}
        
    except Exception as e:
        logger.error(f"Unexpected error extending approval deadline: {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
new_due_date datetime - positional_or_keyword
reason Optional[str] None positional_or_keyword

Parameter Details

user: DocUser object representing the user requesting the deadline extension. Must be either the approval cycle initiator or have MANAGE_APPROVALS permission.

approval_uid: String containing the unique identifier (UID) of the approval cycle whose deadline needs to be extended. Must correspond to an existing approval cycle.

new_due_date: datetime object representing the new deadline for the approval cycle. Must be a future date (after the current time).

reason: Optional string providing the justification for extending the deadline. If provided, it will be added as a comment to the approval cycle and included in notifications.

Return Value

Type: Dict[str, Any]

Returns a dictionary with keys: 'success' (boolean indicating if the operation succeeded), 'message' (string describing the outcome or error), and 'new_due_date' (datetime object of the new deadline, 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 datetime import datetime
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 ResourceNotFoundError, PermissionError, BusinessRuleError, ValidationError, log_controller_action
import logging
import traceback

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_uid exists to retrieve document details for notifications

Required (conditional)

Usage Example

from datetime import datetime, timedelta
from CDocs.models.user_extensions import DocUser
from your_module import extend_approval_deadline

# Get the user extending the deadline
user = DocUser(uid='user123')

# Define the approval cycle UID and new deadline
approval_uid = 'approval_cycle_456'
new_due_date = datetime.now() + timedelta(days=7)
reason = 'Additional time needed for technical review'

# Extend the approval deadline
result = extend_approval_deadline(
    user=user,
    approval_uid=approval_uid,
    new_due_date=new_due_date,
    reason=reason
)

if result['success']:
    print(f"Deadline extended to: {result['new_due_date']}")
else:
    print(f"Error: {result['message']}")

Best Practices

  • Always provide a reason parameter when extending deadlines to maintain clear audit trails
  • Ensure the new_due_date is a timezone-aware datetime object if your system uses timezones
  • Handle the returned dictionary properly, checking the 'success' flag before accessing 'new_due_date'
  • The function is decorated with @log_controller_action('extend_approval_deadline'), so ensure this decorator is applied when using the function
  • This function sends email notifications to all pending approvers, so ensure email configuration is properly set up
  • The function catches and logs exceptions gracefully, returning error messages instead of raising exceptions
  • Only users who initiated the approval or have MANAGE_APPROVALS permission can extend deadlines
  • The new due date must be in the future; past dates will be rejected with a ValidationError
  • Deadline extensions can only be applied to active approval cycles; completed cycles cannot be modified

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function extend_approval_deadline 94.4% similar

    Extends the deadline for an active approval cycle, validating permissions and business rules, then notifying affected approvers.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller.py
  • function extend_review_deadline 84.3% similar

    Extends the deadline for a document review cycle, validating permissions and business rules, then notifying active reviewers of the change.

    From: /tf/active/vicechatdev/CDocs/controllers/review_controller.py
  • function add_approver_to_active_approval_v1 69.5% 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 add_approver_to_active_approval 64.4% 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 close_approval_cycle_v1 64.2% similar

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

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