function extend_approval_deadline
Extends the deadline for an active approval cycle, validating permissions and business rules, then notifying affected approvers.
/tf/active/vicechatdev/CDocs/controllers/approval_controller.py
1280 - 1392
complex
Purpose
This function allows authorized users to extend the due date of an approval cycle that is still pending or in progress. It performs comprehensive validation including permission checks, approval status verification, and date validation. After successfully extending the deadline, it logs the event to the audit trail and sends notifications to all active approvers. This is typically used when approval processes need more time due to unforeseen circumstances or when additional review time is required.
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 for a approval cycle.
Args:
user: User extending the deadline
approval_uid: UID of approval cycle
new_due_date: New due date
reason: Optional reason for extension
Returns:
Dictionary with extension details
Raises:
ResourceNotFoundError: If approval cycle not found
ValidationError: If validation fails
PermissionError: If user doesn't have permission
BusinessRuleError: If extension is not allowed
"""
try:
# Direct permission check at the beginning
logger.info(f"Checking if user {user.uid} has MANAGE_APPROVALS permission")
if not permissions.user_has_permission(user, "MANAGE_APPROVALS"):
logger.warning(f"Permission denied: User {user.uid} attempted to manage approvals without MANAGE_APPROVALS permission")
raise PermissionError("You do not have permission to manage approvals")
logger.info(f"User {user.uid} has permission to manage approvals {approval_uid}")
# Get approval cycle instance
approval_cycle = ApprovalCycle(uid=approval_uid)
if not approval_cycle:
raise ResourceNotFoundError(f"Approval cycle not found: {approval_uid}")
# Check if approval is still active
if approval_cycle.status not in ["PENDING", "IN_PROGRESS"]:
raise BusinessRuleError(f"Cannot extend deadline for approval with status {approval_cycle.status}")
# Validate new due date
if new_due_date <= datetime.now():
raise ValidationError("New due date must be in the future")
if approval_cycle.due_date and new_due_date <= approval_cycle.due_date:
raise ValidationError("New due date must be later than current due date")
# Check if user has permission
if not permissions.user_has_permission(user, "MANAGE_APPROVALS"):
# Check if user is the document owner or approval initiator
document = ControlledDocument(uid=approval_cycle.document_uid)
if not (document and document.owner_uid == user.uid) and approval_cycle.initiated_by_uid != user.uid:
raise PermissionError("User is not authorized to extend this approval deadline")
# Store old due date for audit
old_due_date = approval_cycle.due_date
# Update approval cycle
approval_cycle.due_date = new_due_date
approval_cycle.save()
# Log extension event
audit_trail.log_approval_event(
event_type="APPROVE_DEADLINE_EXTENDED",
user=user,
approval_uid=approval_uid,
details={
"old_due_date": old_due_date.isoformat() if old_due_date else None,
"new_due_date": new_due_date.isoformat(),
"reason": reason
}
)
# Notify active approvers
assignments = approval_cycle.get_approver_assignments()
active_approver_uids = [a.approver_uid for a in assignments if a.status in ["PENDING", "ACTIVE"]]
if active_approver_uids:
document = ControlledDocument(uid=approval_cycle.document_uid)
notifications.send_notification(
notification_type="APPROVE_DEADLINE_EXTENDED",
users=active_approver_uids,
resource_uid=approval_cycle.uid,
resource_type="ApprovalCycle",
message=f"Approval deadline for {document.doc_number if document else 'document'} has been extended",
details={
"approval_uid": approval_uid,
"document_uid": document.uid if document else None,
"doc_number": document.doc_number if document else None,
"title": document.title if document else None,
"new_due_date": new_due_date.isoformat(),
"reason": reason
},
send_email=True,
email_template="approval_deadline_extended"
)
return {
"success": True,
"approval_uid": approval_uid,
"old_due_date": old_due_date,
"new_due_date": new_due_date,
"reason": reason,
"message": "Approval deadline extended successfully"
}
except (ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError) as e:
# Re-raise known errors
raise
except Exception as e:
logger.error(f"Error extending approval deadline: {e}")
raise BusinessRuleError(f"Failed to extend approval deadline: {e}")
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 attempting to extend the deadline. Must have MANAGE_APPROVALS permission, or be the document owner or approval initiator. Used for permission checks and audit logging.
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 in the system.
new_due_date: datetime object representing the new deadline for the approval cycle. Must be in the future and later than the current due date. This will replace the existing due_date on the approval cycle.
reason: Optional string providing justification for the deadline extension. Used for audit trail logging and included in notifications sent to approvers. Can be None if no reason is provided.
Return Value
Type: Dict[str, Any]
Returns a dictionary with keys: 'success' (bool, always True on successful execution), 'approval_uid' (str, the UID of the approval cycle), 'old_due_date' (datetime or None, the previous due date), 'new_due_date' (datetime, the updated due date), 'reason' (str or None, the provided reason), and 'message' (str, success confirmation message).
Dependencies
logginguuidostypingdatetimetracebackCDocs.dbCDocs.config.settingsCDocs.config.permissionsCDocs.models.documentCDocs.models.approvalCDocs.models.user_extensionsCDocs.utils.audit_trailCDocs.utils.notificationsCDocs.controllersCDocs.controllers.share_controllerCDocs.db.db_operations
Required Imports
from datetime import datetime
from typing import Dict, Any, Optional
from CDocs.models.user_extensions import DocUser
from CDocs.models.approval import ApprovalCycle
from CDocs.models.document import ControlledDocument
from CDocs.config import permissions
from CDocs.utils import audit_trail
from CDocs.utils import notifications
from CDocs.controllers import ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError
from CDocs.controllers import log_controller_action
import logging
Usage Example
from datetime import datetime, timedelta
from CDocs.models.user_extensions import DocUser
from your_module import extend_approval_deadline
# Get the user and approval cycle UID
user = DocUser(uid='user123')
approval_uid = 'approval456'
# Set new due date to 7 days from now
new_due_date = datetime.now() + timedelta(days=7)
reason = 'Additional time needed for technical review'
# Extend the deadline
try:
result = extend_approval_deadline(
user=user,
approval_uid=approval_uid,
new_due_date=new_due_date,
reason=reason
)
print(f"Success: {result['message']}")
print(f"Old deadline: {result['old_due_date']}")
print(f"New deadline: {result['new_due_date']}")
except PermissionError as e:
print(f"Permission denied: {e}")
except ValidationError as e:
print(f"Validation failed: {e}")
except BusinessRuleError as e:
print(f"Business rule violation: {e}")
Best Practices
- Always wrap calls in try-except blocks to handle ResourceNotFoundError, ValidationError, PermissionError, and BusinessRuleError exceptions
- Ensure the new_due_date is a timezone-aware datetime object if your system uses timezone-aware datetimes
- Provide a meaningful reason parameter for audit trail purposes and transparency to approvers
- Verify that the user object is properly authenticated and loaded before calling this function
- The function performs duplicate permission checks - the first check at the beginning is the primary gate, the second is redundant and will never execute
- This function is decorated with log_controller_action('extend_approval_deadline') which provides automatic logging
- The function sends email notifications to all active approvers, so ensure email system is properly configured
- Only approval cycles with status 'PENDING' or 'IN_PROGRESS' can have their deadlines extended
- The new due date must be both in the future and later than the current due date
- Consider the impact on approvers' schedules when extending deadlines significantly
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function extend_approval_deadline_v1 94.4% similar
-
function extend_review_deadline 89.4% similar
-
function add_approver_to_active_approval 67.5% similar
-
function add_approver_to_active_approval_v1 65.0% similar
-
function complete_approval 64.9% similar