🔍 Code Extractor

function notify_approval

Maturity: 65

Sends approval notifications to designated approvers for a document version, supporting multiple notification types (requested, reminder, overdue, completed, rejected, signed) with email and in-app notifications.

File:
/tf/active/vicechatdev/CDocs/utils/notifications.py
Lines:
1326 - 1457
Complexity:
moderate

Purpose

This function orchestrates the approval notification workflow by retrieving document and version details, preparing notification content based on the notification type, and dispatching notifications to specified approvers. It handles various approval lifecycle events including initial requests, reminders, overdue notices, completion, rejection, and document signing. The function constructs detailed email templates with document metadata and approval URLs, logs comprehensive debugging information, and gracefully handles errors by returning empty lists on failure.

Source Code

def notify_approval(approval, 
                   notification_type: str,
                   step: Optional[str] = None,
                   approver_uids: Optional[List[str]] = None) -> List[str]:
    """
    Send approval notifications to approvers.
    
    Args:
        approval: Approval instance
        notification_type: Type of notification
        approver_uids: Optional specific approvers to notify (default: all)
        
    Returns:
        List of created notification UIDs
    """
    try:
        # Get document and version details
        version = approval.document_version
        if not version:
            logger.error(f"Could not find document version for approval {approval.uid}")
            return []
            
        document = version.document
        if not document:
            logger.error(f"Could not find document for approval {approval.uid}")
            return []
            
        # Log the document details for debugging
        logger.info(f"notify_approval called for document {document.doc_number} - {document.title}")
        logger.debug(f"Document data: doc_number={document.doc_number}, title={document.title}, doc_type={document.doc_type}")
        logger.debug(f"Version data: version_number={version.version_number}")
        logger.debug(f"Approval data: uid={approval.uid}, due_date={approval.due_date}")
        
        # Get approvers to notify
        if approver_uids is None:
            approver_uids = approval.approver_uids
            
        if not approver_uids:
            logger.warning(f"No approvers to notify for approval {approval.uid}")
            return []
            
        # Prepare notification details
        details = {
            'approval_uid': approval.uid,
            'version_uid': version.uid,
            'doc_uid': document.uid,
            'doc_number': document.doc_number,
            'doc_type': document.doc_type,
            'title': document.title,
            'step': step,
            'version_number': version.version_number,
            'due_date': approval.due_date.strftime('%Y-%m-%d') if approval.due_date else None
        }
        
        # Create message based on notification type
        message = None
        if notification_type == 'APPROVAL_REQUESTED':
            message = f"Please approve {document.doc_number} - {document.title} (v{version.version_number})"
        elif notification_type == 'APPROVAL_REMINDER':
            message = f"Reminder: Your approval of {document.doc_number} (v{version.version_number}) is due soon"
        elif notification_type == 'APPROVAL_OVERDUE':
            message = f"Your approval of {document.doc_number} (v{version.version_number}) is overdue"
        elif notification_type == 'APPROVAL_COMPLETED':
            message = f"The approval process for {document.doc_number} (v{version.version_number}) has been completed"
        elif notification_type == 'APPROVAL_REJECTED':
            message = f"The approval for {document.doc_number} (v{version.version_number}) has been rejected"
        elif notification_type == 'DOCUMENT_SIGNED':
            message = f"Document {document.doc_number} (v{version.version_number}) has been signed"
            
        # Determine email template based on notification type
        email_template = None
        if notification_type == 'APPROVAL_REQUESTED':
            email_template = 'approval_requested'
        elif notification_type == 'APPROVAL_REMINDER':
            email_template = 'approval_reminder'
        elif notification_type == 'APPROVAL_OVERDUE':
            email_template = 'approval_overdue'
        elif notification_type == 'APPROVAL_COMPLETED':
            email_template = 'approval_completed'
        elif notification_type == 'APPROVAL_REJECTED':
            email_template = 'approval_rejected'
        elif notification_type == 'DOCUMENT_SIGNED':
            email_template = 'document_signed'
            
        # Add approval instructions to email data if available
        email_data = {
            'doc_number': document.doc_number,
            'title': document.title,
            'doc_type': document.doc_type,
            'version_number': version.version_number,
            'due_date': approval.due_date.strftime('%B %d, %Y') if approval.due_date else 'Not specified',
            'document_url': f"{settings.APP_URL}/document/{document.uid}",
            'approval_url': f"{settings.APP_URL}/approval/{approval.uid}",
            'cdocs_app_url': 'https://cdocs.vicebio.com',
            'cdocs_app_text': 'Access the CDocs Application'
        }
        
        # Debug: Log the actual email_data being created
        logger.info(f"notify_approval: Creating email_data for template '{email_template}'")
        logger.info(f"notify_approval: Document attributes - doc_number: '{document.doc_number}', title: '{document.title}', doc_type: '{document.doc_type}'")
        logger.info(f"notify_approval: Version attributes - version_number: '{version.version_number}'")
        logger.info(f"notify_approval: Email_data created: {email_data}")
        
        # Log the email data being constructed
        logger.info(f"Constructed email_data for template '{email_template}':")
        for key, value in email_data.items():
            logger.info(f"  {key}: {value}")
        
        if approval.instructions:
            email_data['instructions'] = approval.instructions
            logger.debug(f"Added instructions: {approval.instructions}")
        
        if step:
            email_data['step'] = step
            logger.debug(f"Added step: {step}")
            
        # Send notification
        return send_notification(
            notification_type=notification_type,
            users=approver_uids,
            resource_uid=approval.uid,
            resource_type='Approval',
            message=message,
            details=details,
            send_email=True,
            email_template=email_template,
            email_data=email_data
        )
        
    except Exception as e:
        logger.error(f"Error sending approval notification: {e}")
        return []

Parameters

Name Type Default Kind
approval - - positional_or_keyword
notification_type str - positional_or_keyword
step Optional[str] None positional_or_keyword
approver_uids Optional[List[str]] None positional_or_keyword

Parameter Details

approval: An Approval model instance containing approval details including uid, document_version relationship, approver_uids list, due_date, and optional instructions. Must have valid relationships to document_version and document.

notification_type: String specifying the type of notification to send. Valid values: 'APPROVAL_REQUESTED', 'APPROVAL_REMINDER', 'APPROVAL_OVERDUE', 'APPROVAL_COMPLETED', 'APPROVAL_REJECTED', 'DOCUMENT_SIGNED'. Determines the message content and email template used.

step: Optional string indicating the current approval step or stage in a multi-step approval process. Included in notification details and email data when provided.

approver_uids: Optional list of user UID strings to notify. If None, defaults to all approvers from approval.approver_uids. Allows targeting specific approvers for notifications rather than the entire approval group.

Return Value

Type: List[str]

Returns a list of strings containing the UIDs of successfully created notifications. Returns an empty list if no approvers are specified, if document/version retrieval fails, or if an exception occurs during notification processing. The UIDs can be used to track or reference the created notifications.

Dependencies

  • logging
  • typing
  • datetime
  • CDocs
  • CDocs.config
  • CDocs.models.user_extensions
  • CDocs.utils
  • CDocs.controllers.document_controller
  • models.review
  • models.approval

Required Imports

import logging
from typing import List, Optional
from datetime import datetime
from CDocs.config import settings
from models.approval import Approval

Usage Example

# Assuming you have an approval instance from the database
from models.approval import Approval
from typing import List

# Get an approval instance
approval = Approval.query.filter_by(uid='approval-123').first()

# Send initial approval request to all approvers
notification_uids = notify_approval(
    approval=approval,
    notification_type='APPROVAL_REQUESTED',
    step='Initial Review'
)
print(f"Created {len(notification_uids)} notifications")

# Send reminder to specific approvers
specific_approvers = ['user-uid-1', 'user-uid-2']
reminder_uids = notify_approval(
    approval=approval,
    notification_type='APPROVAL_REMINDER',
    step='Final Review',
    approver_uids=specific_approvers
)

# Send overdue notification
overdue_uids = notify_approval(
    approval=approval,
    notification_type='APPROVAL_OVERDUE'
)

# Notify completion
completion_uids = notify_approval(
    approval=approval,
    notification_type='APPROVAL_COMPLETED'
)

Best Practices

  • Ensure the approval instance has valid relationships to document_version and document before calling this function
  • The function logs extensively at INFO and DEBUG levels; configure logging appropriately for production environments
  • Handle the returned list of notification UIDs to track notification success/failure
  • Validate notification_type parameter against the supported types to avoid silent failures with None messages
  • The function gracefully handles errors by returning empty lists; check return value length to detect failures
  • Due dates are formatted differently for details (YYYY-MM-DD) and email display (Month DD, YYYY)
  • Email templates must be properly configured in the email system for notifications to render correctly
  • The function depends on send_notification being available in the same module scope
  • Consider implementing retry logic for failed notifications at a higher level
  • The approver_uids parameter allows selective notification, useful for escalation or targeted reminders

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function complete_approval_v1 70.0% 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 add_approver_to_active_approval_v1 69.1% 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 send_notification 68.8% similar

    Sends in-app notifications to one or more users and optionally sends corresponding email notifications using templates.

    From: /tf/active/vicechatdev/CDocs/utils/notifications.py
  • function create_approval_cycle 68.6% similar

    Creates a new approval cycle for a document, assigning approvers with configurable workflow options (sequential/parallel), instructions, and due dates.

    From: /tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
  • function notify_review 68.0% similar

    Sends review notifications to specified reviewers for a document review cycle, supporting multiple notification types (requested, reminder, overdue, completed).

    From: /tf/active/vicechatdev/CDocs/utils/notifications.py
← Back to Browse