🔍 Code Extractor

class WorkflowControllerBase

Maturity: 54

Abstract base class that defines the interface for workflow controllers managing document review and approval processes.

File:
/tf/active/vicechatdev/CDocs single class/controllers/workflow_controller_base.py
Lines:
21 - 510
Complexity:
complex

Purpose

WorkflowControllerBase serves as an abstract base class for implementing workflow management systems (reviews, approvals, etc.) in a document management system. It defines a comprehensive interface for creating and managing workflow cycles, assignments, participants, comments, and notifications. Subclasses must implement all abstract methods to provide concrete functionality for specific workflow types. The class handles the complete lifecycle of workflows including creation, participant management, status updates, completion, cancellation, and notifications.

Source Code

class WorkflowControllerBase:
    """Base controller for workflow processes like reviews and approvals."""
    
    def __init__(self):
        """Initialize the base workflow controller."""
        self.workflow_type = None  # Should be set by subclasses e.g., 'REVIEW' or 'APPROVAL'
    
    def create_cycle(self, document_version_uid: str, 
                    user_uids: List[str],
                    due_date: Optional[datetime] = None,
                    instructions: str = '',
                    sequential: bool = False,
                    required_approval_percentage: int = 100,
                    initiated_by_uid: Optional[str] = None,
                    notify_users: bool = True) -> Optional[Dict[str, Any]]:
        """
        Create a new workflow cycle.
        
        Args:
            document_version_uid: UID of the document version
            user_uids: List of user UIDs to assign
            due_date: Optional due date (default: based on settings)
            instructions: Instructions for assignees
            sequential: Whether workflow should be sequential
            required_approval_percentage: Percentage of approvals required
            initiated_by_uid: UID of the user who initiated the workflow
            notify_users: Whether to send notifications to assigned users
            
        Returns:
            Dictionary with the created cycle information or None if failed
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement create_cycle")
    
    def get_cycle_by_uid(self, cycle_uid: str) -> Optional[Dict[str, Any]]:
        """
        Get workflow cycle information by UID.
        
        Args:
            cycle_uid: UID of the workflow cycle
            
        Returns:
            Dictionary with cycle information or None if not found
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_cycle_by_uid")
    
    def get_cycles_for_document(self, document_uid: str) -> List[Dict[str, Any]]:
        """
        Get all workflow cycles for a document.
        
        Args:
            document_uid: UID of the document
            
        Returns:
            List of dictionaries with cycle information
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_cycles_for_document")
    
    def get_cycles_for_document_version(self, version_uid: str) -> List[Dict[str, Any]]:
        """
        Get all workflow cycles for a document version.
        
        Args:
            version_uid: UID of the document version
            
        Returns:
            List of dictionaries with cycle information
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_cycles_for_document_version")
    
    def get_current_cycle_for_document(self, document_uid: str) -> Optional[Dict[str, Any]]:
        """
        Get the current active workflow cycle for a document.
        
        Args:
            document_uid: UID of the document
            
        Returns:
            Dictionary with cycle information or None if no active cycle
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_current_cycle_for_document")
    
    def get_assignments_for_cycle(self, cycle_uid: str) -> List[Dict[str, Any]]:
        """
        Get all assignments for a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            
        Returns:
            List of dictionaries with assignment information
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_assignments_for_cycle")
    
    def get_assignment_by_uid(self, assignment_uid: str) -> Optional[Dict[str, Any]]:
        """
        Get assignment information by UID.
        
        Args:
            assignment_uid: UID of the assignment
            
        Returns:
            Dictionary with assignment information or None if not found
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_assignment_by_uid")
    
    def get_assignment_for_user(self, cycle_uid: str, user_uid: str) -> Optional[Dict[str, Any]]:
        """
        Get assignment for a specific user in a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            user_uid: UID of the user
            
        Returns:
            Dictionary with assignment information or None if not found
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_assignment_for_user")
    
    def get_assignments_for_user(self, user_uid: str, 
                                status_filter: Optional[List[str]] = None,
                                limit: int = 100, 
                                offset: int = 0) -> Tuple[List[Dict[str, Any]], int]:
        """
        Get all assignments for a user.
        
        Args:
            user_uid: UID of the user
            status_filter: Optional list of status values to filter by
            limit: Maximum number of results to return
            offset: Number of results to skip
            
        Returns:
            Tuple of (list of assignment dictionaries, total count)
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_assignments_for_user")
    
    def update_cycle_status(self, cycle_uid: str, status: str) -> bool:
        """
        Update the status of a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            status: New status value
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement update_cycle_status")
    
    def complete_cycle(self, cycle_uid: str, decision: str, comment: Optional[str] = None) -> bool:
        """
        Complete a workflow cycle with a decision.
        
        Args:
            cycle_uid: UID of the workflow cycle
            decision: Decision value (e.g., 'APPROVED' or 'REJECTED')
            comment: Optional comment about the decision
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement complete_cycle")
    
    def cancel_cycle(self, cycle_uid: str, reason: Optional[str] = None) -> bool:
        """
        Cancel a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            reason: Optional reason for cancellation
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement cancel_cycle")
    
    def add_participant(self, cycle_uid: str, user_uid: str, sequence_order: int = 0) -> bool:
        """
        Add a participant to a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            user_uid: UID of the user to add
            sequence_order: Order in the sequence (for sequential workflows)
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement add_participant")
    
    def remove_participant(self, cycle_uid: str, user_uid: str, reason: Optional[str] = None) -> bool:
        """
        Remove a participant from a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            user_uid: UID of the user to remove
            reason: Optional reason for removal
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement remove_participant")
    
    def update_assignment_status(self, assignment_uid: str, status: str) -> bool:
        """
        Update the status of an assignment.
        
        Args:
            assignment_uid: UID of the assignment
            status: New status value
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement update_assignment_status")
    
    def complete_assignment(self, assignment_uid: str, 
                           decision: str, 
                           comments: Optional[str] = None) -> bool:
        """
        Complete an assignment with a decision.
        
        Args:
            assignment_uid: UID of the assignment
            decision: Decision value (e.g., 'APPROVED' or 'REJECTED')
            comments: Optional comments about the decision
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement complete_assignment")
    
    def add_comment(self, cycle_uid: str, 
                   user_uid: str, 
                   text: str,
                   requires_resolution: bool = False,
                   comment_type: str = 'GENERAL',
                   parent_comment_uid: Optional[str] = None,
                   location: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
        """
        Add a comment to a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            user_uid: UID of the user making the comment
            text: Comment text
            requires_resolution: Whether the comment requires resolution
            comment_type: Type of comment
            parent_comment_uid: UID of parent comment (for replies)
            location: Location information (e.g., page number, coordinates)
            
        Returns:
            Dictionary with the created comment information or None if failed
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement add_comment")
    
    def get_comments(self, cycle_uid: str) -> List[Dict[str, Any]]:
        """
        Get all comments for a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            
        Returns:
            List of dictionaries with comment information
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_comments")
    
    def resolve_comment(self, comment_uid: str, resolution_text: str) -> bool:
        """
        Resolve a comment.
        
        Args:
            comment_uid: UID of the comment
            resolution_text: Resolution text
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement resolve_comment")
    
    def get_comment_by_uid(self, comment_uid: str) -> Optional[Dict[str, Any]]:
        """
        Get comment information by UID.
        
        Args:
            comment_uid: UID of the comment
            
        Returns:
            Dictionary with comment information or None if not found
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_comment_by_uid")
    
    def update_due_date(self, cycle_uid: str, due_date: datetime) -> bool:
        """
        Update the due date for a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            due_date: New due date
            
        Returns:
            Boolean indicating success
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement update_due_date")
    
    def get_overdue_assignments(self) -> List[Dict[str, Any]]:
        """
        Get all overdue assignments.
        
        Returns:
            List of dictionaries with overdue assignment information
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_overdue_assignments")
    
    def notify_participant(self, assignment_uid: str, message: Optional[str] = None) -> bool:
        """
        Send a notification to a workflow participant.
        
        Args:
            assignment_uid: UID of the assignment
            message: Optional custom message
            
        Returns:
            Boolean indicating success
        """
        try:
            # Get assignment details
            assignment = self.get_assignment_by_uid(assignment_uid)
            if not assignment:
                logger.error(f"Assignment {assignment_uid} not found for notification")
                return False
                
            user_uid = assignment.get('user_uid')
            if not user_uid:
                logger.error(f"No user UID found for assignment {assignment_uid}")
                return False
                
            # Get user details
            user = DocUser.get_by_uid(user_uid)
            if not user:
                logger.error(f"User {user_uid} not found for notification")
                return False
                
            # Get cycle details
            cycle_uid = assignment.get('cycle_uid')
            if not cycle_uid:
                logger.error(f"No cycle UID found for assignment {assignment_uid}")
                return False
                
            cycle = self.get_cycle_by_uid(cycle_uid)
            if not cycle:
                logger.error(f"Cycle {cycle_uid} not found for notification")
                return False
                
            # Get document details
            document_version_uid = cycle.get('document_version_uid')
            if not document_version_uid:
                logger.error(f"No document version UID found for cycle {cycle_uid}")
                return False
                
            from CDocs.models.document import DocumentVersion
            doc_version = DocumentVersion(uid=document_version_uid)
            if not doc_version:
                logger.error(f"Document version {document_version_uid} not found")
                return False
                
            document = doc_version.document
            if not document:
                logger.error(f"Document not found for version {document_version_uid}")
                return False
                
            # Prepare notification details
            title = f"{self.workflow_type} Request: {document.title}"
            if not message:
                message = f"You have been assigned to {self.workflow_type.lower()} document {document.doc_number}: {document.title}"
                
            # Send notification
            notification_data = {
                'recipient_uid': user_uid,
                'title': title,
                'message': message,
                'link_url': f"/document/{document.uid}/version/{doc_version.uid}/{self.workflow_type.lower()}",
                'notification_type': f"{self.workflow_type}_REQUEST",
                'source_uid': cycle_uid,
                'priority': 'MEDIUM'
            }
            
            return send_notification(notification_data)
            
        except Exception as e:
            logger.error(f"Error sending notification to participant: {e}")
            import traceback
            logger.error(traceback.format_exc())
            return False

    def notify_all_participants(self, cycle_uid: str, message: Optional[str] = None) -> bool:
        """
        Send notifications to all participants in a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            message: Optional custom message
            
        Returns:
            Boolean indicating overall success
        """
        try:
            # Get all assignments for this cycle
            assignments = self.get_assignments_for_cycle(cycle_uid)
            if not assignments:
                logger.warning(f"No assignments found for cycle {cycle_uid}")
                return False
                
            # Send notification to each participant
            success_count = 0
            for assignment in assignments:
                if self.notify_participant(assignment['UID'], message):
                    success_count += 1
                    
            # Return true if at least one notification was sent successfully
            return success_count > 0
            
        except Exception as e:
            logger.error(f"Error notifying all participants: {e}")
            return False
    
    def get_workflow_statistics(self) -> Dict[str, Any]:
        """
        Get statistics about workflow cycles.
        
        Returns:
            Dictionary with statistics information
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement get_workflow_statistics")
    
    def search_cycles(self, query: Dict[str, Any], 
                     limit: int = 100, 
                     offset: int = 0) -> Tuple[List[Dict[str, Any]], int]:
        """
        Search for workflow cycles based on criteria.
        
        Args:
            query: Dictionary with search criteria
            limit: Maximum number of results to return
            offset: Number of results to skip
            
        Returns:
            Tuple of (list of cycle dictionaries, total count)
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement search_cycles")
    
    def is_user_participant(self, cycle_uid: str, user_uid: str) -> bool:
        """
        Check if a user is a participant in a workflow cycle.
        
        Args:
            cycle_uid: UID of the workflow cycle
            user_uid: UID of the user to check
            
        Returns:
            Boolean indicating if user is a participant
        """
        # This is an abstract method that should be implemented by subclasses
        raise NotImplementedError("Subclasses must implement is_user_participant")

Parameters

Name Type Default Kind
bases - -

Parameter Details

__init__: No parameters required. The constructor initializes the workflow_type attribute to None, which should be set by subclasses to identify the specific workflow type (e.g., 'REVIEW' or 'APPROVAL').

Return Value

Instantiation returns a WorkflowControllerBase object. Methods return various types: cycle/assignment/comment creation methods return Optional[Dict[str, Any]] with the created object data or None on failure; query methods return List[Dict[str, Any]] for collections or Optional[Dict[str, Any]] for single items; status update methods return bool indicating success; search methods return Tuple[List[Dict[str, Any]], int] containing results and total count; notification methods return bool indicating success.

Class Interface

Methods

__init__(self)

Purpose: Initialize the base workflow controller with workflow_type set to None

Returns: None

create_cycle(self, document_version_uid: str, user_uids: List[str], due_date: Optional[datetime] = None, instructions: str = '', sequential: bool = False, required_approval_percentage: int = 100, initiated_by_uid: Optional[str] = None, notify_users: bool = True) -> Optional[Dict[str, Any]]

Purpose: Create a new workflow cycle for a document version with assigned users

Parameters:

  • document_version_uid: UID of the document version to create workflow for
  • user_uids: List of user UIDs to assign to the workflow
  • due_date: Optional due date for the workflow (defaults to system settings if not provided)
  • instructions: Instructions or guidance text for workflow participants
  • sequential: If True, workflow proceeds sequentially through users; if False, all users work in parallel
  • required_approval_percentage: Percentage of approvals required for cycle completion (1-100)
  • initiated_by_uid: UID of the user who initiated the workflow
  • notify_users: If True, send notifications to assigned users upon cycle creation

Returns: Dictionary containing created cycle information including UID, status, and metadata, or None if creation failed

get_cycle_by_uid(self, cycle_uid: str) -> Optional[Dict[str, Any]]

Purpose: Retrieve workflow cycle information by its unique identifier

Parameters:

  • cycle_uid: Unique identifier of the workflow cycle

Returns: Dictionary with cycle information including status, participants, dates, or None if not found

get_cycles_for_document(self, document_uid: str) -> List[Dict[str, Any]]

Purpose: Get all workflow cycles associated with a document across all versions

Parameters:

  • document_uid: UID of the document

Returns: List of dictionaries containing cycle information for all cycles related to the document

get_cycles_for_document_version(self, version_uid: str) -> List[Dict[str, Any]]

Purpose: Get all workflow cycles for a specific document version

Parameters:

  • version_uid: UID of the document version

Returns: List of dictionaries containing cycle information for the specified version

get_current_cycle_for_document(self, document_uid: str) -> Optional[Dict[str, Any]]

Purpose: Get the currently active workflow cycle for a document

Parameters:

  • document_uid: UID of the document

Returns: Dictionary with active cycle information, or None if no active cycle exists

get_assignments_for_cycle(self, cycle_uid: str) -> List[Dict[str, Any]]

Purpose: Retrieve all user assignments for a specific workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle

Returns: List of dictionaries containing assignment information including user, status, and completion details

get_assignment_by_uid(self, assignment_uid: str) -> Optional[Dict[str, Any]]

Purpose: Retrieve a specific assignment by its unique identifier

Parameters:

  • assignment_uid: UID of the assignment

Returns: Dictionary with assignment details including user, cycle, status, decision, or None if not found

get_assignment_for_user(self, cycle_uid: str, user_uid: str) -> Optional[Dict[str, Any]]

Purpose: Get the assignment for a specific user within a workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle
  • user_uid: UID of the user

Returns: Dictionary with assignment information for the user in the cycle, or None if not found

get_assignments_for_user(self, user_uid: str, status_filter: Optional[List[str]] = None, limit: int = 100, offset: int = 0) -> Tuple[List[Dict[str, Any]], int]

Purpose: Get all workflow assignments for a user with optional filtering and pagination

Parameters:

  • user_uid: UID of the user
  • status_filter: Optional list of status values to filter assignments (e.g., ['PENDING', 'IN_PROGRESS'])
  • limit: Maximum number of results to return
  • offset: Number of results to skip for pagination

Returns: Tuple containing (list of assignment dictionaries, total count of matching assignments)

update_cycle_status(self, cycle_uid: str, status: str) -> bool

Purpose: Update the status of a workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle
  • status: New status value (e.g., 'ACTIVE', 'COMPLETED', 'CANCELLED')

Returns: True if status was updated successfully, False otherwise

complete_cycle(self, cycle_uid: str, decision: str, comment: Optional[str] = None) -> bool

Purpose: Mark a workflow cycle as complete with a final decision

Parameters:

  • cycle_uid: UID of the workflow cycle
  • decision: Final decision value (e.g., 'APPROVED', 'REJECTED')
  • comment: Optional comment explaining the decision

Returns: True if cycle was completed successfully, False otherwise

cancel_cycle(self, cycle_uid: str, reason: Optional[str] = None) -> bool

Purpose: Cancel an active workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle
  • reason: Optional reason for cancellation

Returns: True if cycle was cancelled successfully, False otherwise

add_participant(self, cycle_uid: str, user_uid: str, sequence_order: int = 0) -> bool

Purpose: Add a new participant to an existing workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle
  • user_uid: UID of the user to add
  • sequence_order: Order position for sequential workflows (0 for parallel workflows)

Returns: True if participant was added successfully, False otherwise

remove_participant(self, cycle_uid: str, user_uid: str, reason: Optional[str] = None) -> bool

Purpose: Remove a participant from a workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle
  • user_uid: UID of the user to remove
  • reason: Optional reason for removal

Returns: True if participant was removed successfully, False otherwise

update_assignment_status(self, assignment_uid: str, status: str) -> bool

Purpose: Update the status of a user's assignment

Parameters:

  • assignment_uid: UID of the assignment
  • status: New status value (e.g., 'PENDING', 'IN_PROGRESS', 'COMPLETED')

Returns: True if status was updated successfully, False otherwise

complete_assignment(self, assignment_uid: str, decision: str, comments: Optional[str] = None) -> bool

Purpose: Mark an assignment as complete with a decision

Parameters:

  • assignment_uid: UID of the assignment
  • decision: Decision value (e.g., 'APPROVED', 'REJECTED', 'NEEDS_REVISION')
  • comments: Optional comments about the decision

Returns: True if assignment was completed successfully, False otherwise

add_comment(self, cycle_uid: str, user_uid: str, text: str, requires_resolution: bool = False, comment_type: str = 'GENERAL', parent_comment_uid: Optional[str] = None, location: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]

Purpose: Add a comment to a workflow cycle with optional threading and location data

Parameters:

  • cycle_uid: UID of the workflow cycle
  • user_uid: UID of the user making the comment
  • text: Comment text content
  • requires_resolution: If True, comment must be resolved before cycle completion
  • comment_type: Type of comment (e.g., 'GENERAL', 'QUESTION', 'ISSUE')
  • parent_comment_uid: UID of parent comment for threaded replies
  • location: Optional location data (e.g., {'page': 5, 'x': 100, 'y': 200})

Returns: Dictionary with created comment information including UID and timestamp, or None if failed

get_comments(self, cycle_uid: str) -> List[Dict[str, Any]]

Purpose: Retrieve all comments for a workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle

Returns: List of dictionaries containing comment information including text, author, timestamp, and resolution status

resolve_comment(self, comment_uid: str, resolution_text: str) -> bool

Purpose: Mark a comment as resolved with resolution text

Parameters:

  • comment_uid: UID of the comment
  • resolution_text: Text explaining how the comment was resolved

Returns: True if comment was resolved successfully, False otherwise

get_comment_by_uid(self, comment_uid: str) -> Optional[Dict[str, Any]]

Purpose: Retrieve a specific comment by its unique identifier

Parameters:

  • comment_uid: UID of the comment

Returns: Dictionary with comment details including text, author, timestamp, resolution status, or None if not found

update_due_date(self, cycle_uid: str, due_date: datetime) -> bool

Purpose: Update the due date for a workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle
  • due_date: New due date as datetime object

Returns: True if due date was updated successfully, False otherwise

get_overdue_assignments(self) -> List[Dict[str, Any]]

Purpose: Retrieve all assignments that are past their due date

Returns: List of dictionaries containing overdue assignment information

notify_participant(self, assignment_uid: str, message: Optional[str] = None) -> bool

Purpose: Send a notification to a workflow participant about their assignment (fully implemented method)

Parameters:

  • assignment_uid: UID of the assignment
  • message: Optional custom message (defaults to standard workflow notification)

Returns: True if notification was sent successfully, False otherwise

notify_all_participants(self, cycle_uid: str, message: Optional[str] = None) -> bool

Purpose: Send notifications to all participants in a workflow cycle (fully implemented method)

Parameters:

  • cycle_uid: UID of the workflow cycle
  • message: Optional custom message for all participants

Returns: True if at least one notification was sent successfully, False if all failed

get_workflow_statistics(self) -> Dict[str, Any]

Purpose: Get statistical information about workflow cycles

Returns: Dictionary with statistics such as total cycles, completion rates, average duration, etc.

search_cycles(self, query: Dict[str, Any], limit: int = 100, offset: int = 0) -> Tuple[List[Dict[str, Any]], int]

Purpose: Search for workflow cycles based on various criteria with pagination

Parameters:

  • query: Dictionary with search criteria (e.g., {'status': 'ACTIVE', 'user_uid': 'user123'})
  • limit: Maximum number of results to return
  • offset: Number of results to skip for pagination

Returns: Tuple containing (list of matching cycle dictionaries, total count of matches)

is_user_participant(self, cycle_uid: str, user_uid: str) -> bool

Purpose: Check if a user is a participant in a workflow cycle

Parameters:

  • cycle_uid: UID of the workflow cycle
  • user_uid: UID of the user to check

Returns: True if user is a participant in the cycle, False otherwise

Attributes

Name Type Description Scope
workflow_type Optional[str] Identifies the type of workflow (e.g., 'REVIEW', 'APPROVAL'). Set to None in base class, must be set by subclasses in their __init__ method instance

Dependencies

  • logging
  • uuid
  • typing
  • datetime
  • CDocs
  • traceback

Required Imports

import logging
import uuid
from typing import Dict, List, Any, Optional, Union, Tuple
from datetime import datetime, timedelta
from CDocs import db
from CDocs.config import settings
from CDocs.db.schema_manager import NodeLabels, RelTypes
from CDocs.models.user_extensions import DocUser
from CDocs.utils.notifications import send_notification
import traceback

Conditional/Optional Imports

These imports are only needed under specific conditions:

from CDocs.models.document import DocumentVersion

Condition: only when notify_participant method is called to retrieve document version details

Required (conditional)

Usage Example

# This is an abstract base class - must be subclassed
class ReviewController(WorkflowControllerBase):
    def __init__(self):
        super().__init__()
        self.workflow_type = 'REVIEW'
    
    def create_cycle(self, document_version_uid, user_uids, **kwargs):
        # Implement cycle creation logic
        return {'UID': 'cycle-123', 'status': 'ACTIVE'}
    
    # Implement all other abstract methods...

# Usage:
controller = ReviewController()

# Create a review cycle
cycle = controller.create_cycle(
    document_version_uid='doc-v1-uid',
    user_uids=['user1-uid', 'user2-uid'],
    due_date=datetime.now() + timedelta(days=7),
    instructions='Please review and provide feedback',
    sequential=False,
    required_approval_percentage=100,
    initiated_by_uid='manager-uid',
    notify_users=True
)

# Get assignments for the cycle
assignments = controller.get_assignments_for_cycle(cycle['UID'])

# Complete an assignment
controller.complete_assignment(
    assignment_uid=assignments[0]['UID'],
    decision='APPROVED',
    comments='Looks good to me'
)

# Add a comment
controller.add_comment(
    cycle_uid=cycle['UID'],
    user_uid='user1-uid',
    text='Please clarify section 3',
    requires_resolution=True,
    comment_type='QUESTION'
)

# Notify all participants
controller.notify_all_participants(
    cycle_uid=cycle['UID'],
    message='Reminder: Review due in 2 days'
)

Best Practices

  • This is an abstract base class - never instantiate directly, always create a subclass that implements all abstract methods
  • Subclasses must set self.workflow_type in their __init__ method to identify the workflow type (e.g., 'REVIEW', 'APPROVAL')
  • All methods that raise NotImplementedError must be overridden in subclasses with concrete implementations
  • The notify_participant and notify_all_participants methods are fully implemented and can be used as-is or overridden
  • Error handling is built into notification methods with comprehensive logging - ensure logger is configured
  • Methods follow a consistent pattern: cycle management, assignment management, comment management, and notification methods
  • Use the get_assignment_by_uid method before calling notify_participant to ensure assignment exists
  • Sequential workflows should use the sequence_order parameter in add_participant method
  • Status updates should be validated against allowed status values in subclass implementations
  • The required_approval_percentage parameter allows for partial approval workflows (e.g., 75% approval required)
  • Comments support threading via parent_comment_uid and can include location data for document annotations
  • Always check return values: None indicates failure for Optional returns, False indicates failure for bool returns
  • Use pagination parameters (limit, offset) in search and list methods to handle large result sets
  • The notify_users parameter in create_cycle allows control over automatic notifications at cycle creation

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class ReviewControllerBase 88.4% similar

    Abstract base controller class for managing review workflow processes, providing core functionality for handling review cycles, comments, and completion checks.

    From: /tf/active/vicechatdev/CDocs single class/controllers/workflow_controller_base.py
  • class ApprovalControllerBase 84.8% similar

    Abstract base controller class for managing approval workflow processes, providing a template for approval cycle operations and workflow template management.

    From: /tf/active/vicechatdev/CDocs single class/controllers/workflow_controller_base.py
  • class WorkflowCycleBase 81.4% similar

    Base class for workflow cycles (ReviewCycle and ApprovalCycle) that manages workflow lifecycle, status tracking, and common properties for document review and approval processes.

    From: /tf/active/vicechatdev/CDocs single class/models/workflow_base.py
  • class AssignmentBase 74.0% similar

    Base class for managing assignment lifecycle in a document review/approval workflow system, tracking status, timestamps, user assignments, and decisions.

    From: /tf/active/vicechatdev/CDocs single class/models/workflow_base.py
  • class WorkflowPanelBase 73.6% similar

    Base class for workflow panels (review and approval) that provides common functionality and UI components.

    From: /tf/active/vicechatdev/CDocs single class/ui/workflow_panel_base.py
← Back to Browse