🔍 Code Extractor

class AssignmentBase

Maturity: 50

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

File:
/tf/active/vicechatdev/CDocs single class/models/workflow_base.py
Lines:
315 - 528
Complexity:
moderate

Purpose

AssignmentBase provides a foundation for reviewer and approver assignments in a document workflow system. It manages assignment state (pending, in progress, completed, rejected, skipped), tracks timestamps (assigned, started, completed, due dates), stores user information, handles decisions and comments, and provides methods for assignment lifecycle operations. This class is designed to be subclassed by specific assignment types (ReviewerAssignment, ApproverAssignment) that implement persistence and notification mechanisms.

Source Code

class AssignmentBase:
    """Base class for assignments (ReviewerAssignment and ApproverAssignment)."""
    
    def __init__(self, data=None):
        """Initialize with optional data dictionary."""
        self._data = data or {}
        self._modified = False
        
        # Set default values if not provided
        if 'UID' not in self._data:
            self._data['UID'] = str(uuid.uuid4())
            self._modified = True
            
        if 'assigned_at' not in self._data:
            self._data['assigned_at'] = datetime.now().isoformat()
            self._modified = True
            
        if 'status' not in self._data:
            self._data['status'] = AssignmentStatus.PENDING
            self._modified = True
    
    @property
    def uid(self) -> str:
        """Get the UID."""
        return self._data.get('UID', '')
    
    @property
    def status(self) -> str:
        """Get the status."""
        return self._data.get('status', AssignmentStatus.PENDING)
    
    @status.setter
    def status(self, value: str) -> None:
        """Set the status."""
        self._data['status'] = value
        self._modified = True
    
    @property
    def role(self) -> str:
        """Get the role."""
        return self._data.get('role', '')
    
    @role.setter
    def role(self, value: str) -> None:
        """Set the role."""
        self._data['role'] = value
        self._modified = True
    
    @property
    def order(self) -> str:
        """Get the order."""
        return self._data.get('order', '')
    
    @order.setter
    def order(self, value: str) -> None:
        """Set the order."""
        self._data['order'] = value
        self._modified = True
    
    @property
    def assigned_at(self) -> str:
        """Get the assignment timestamp."""
        return self._data.get('assigned_at', '')
    
    @property
    def started_at(self) -> Optional[str]:
        """Get the start timestamp."""
        return self._data.get('started_at')
    
    @started_at.setter
    def started_at(self, value: Optional[str]) -> None:
        """Set the start timestamp."""
        self._data['started_at'] = value
        self._modified = True
    
    @property
    def completed_at(self) -> Optional[str]:
        """Get the completion timestamp."""
        return self._data.get('completed_at')
    
    @completed_at.setter
    def completed_at(self, value: Optional[str]) -> None:
        """Set the completion timestamp."""
        self._data['completed_at'] = value
        self._modified = True
    
    @property
    def due_date(self) -> Optional[str]:
        """Get the due date."""
        return self._data.get('due_date')
    
    @due_date.setter
    def due_date(self, value: Optional[str]) -> None:
        """Set the due date."""
        self._data['due_date'] = value
        self._modified = True
    
    @property
    def user_uid(self) -> str:
        """Get the UID of the assigned user."""
        return self._data.get('user_uid', '')
    
    @user_uid.setter
    def user_uid(self, value: str) -> None:
        """Set the UID of the assigned user."""
        self._data['user_uid'] = value
        self._modified = True
    
    @property
    def user_name(self) -> str:
        """Get the name of the assigned user."""
        return self._data.get('user_name', '')
    
    @user_name.setter
    def user_name(self, value: str) -> None:
        """Set the name of the assigned user."""
        self._data['user_name'] = value
        self._modified = True
    
    @property
    def decision(self) -> Optional[str]:
        """Get the assignment decision."""
        return self._data.get('decision')
    
    @decision.setter
    def decision(self, value: Optional[str]) -> None:
        """Set the assignment decision."""
        self._data['decision'] = value
        self._modified = True
    
    @property
    def comment(self) -> str:
        """Get the assignment comment."""
        return self._data.get('comment', '')
    
    @comment.setter
    def comment(self, value: str) -> None:
        """Set the assignment comment."""
        self._data['comment'] = value
        self._modified = True
    
    def get_user(self):
        """Get the user object for this assignment."""
        from CDocs.models.user_extensions import DocUser
        if not self.user_uid:
            return None
        return DocUser.get_by_uid(self.user_uid)
    
    def notify_assignment(self) -> bool:
        """Notify the assigned user about this assignment."""
        # Implemented in subclasses to use appropriate notification mechanisms
        return False
    
    def is_overdue(self) -> bool:
        """Check if assignment is overdue."""
        return (
            self.due_date is not None 
            and datetime.fromisoformat(self.due_date) < datetime.now()
            and self.status not in [AssignmentStatus.COMPLETED, AssignmentStatus.REJECTED, AssignmentStatus.SKIPPED]
        )
    
    def start_assignment(self) -> bool:
        """Start working on the assignment."""
        if self.status != AssignmentStatus.PENDING:
            return False
        
        self.status = AssignmentStatus.IN_PROGRESS
        self.started_at = datetime.now().isoformat()
        self._modified = True
        return self.save()
    
    def complete_assignment(self, approve: bool = True) -> bool:
        """Complete the assignment with approval or rejection."""
        if self.status not in [AssignmentStatus.PENDING, AssignmentStatus.IN_PROGRESS]:
            return False
        
        self.status = AssignmentStatus.COMPLETED if approve else AssignmentStatus.REJECTED
        self.completed_at = datetime.now().isoformat()
        self._modified = True
        
        if not self.save():
            return False
        
        # Update parent cycle status
        self._update_cycle_status()
        
        return True
    
    def skip_assignment(self) -> bool:
        """Mark the assignment as skipped."""
        if self.status in [AssignmentStatus.COMPLETED, AssignmentStatus.REJECTED, AssignmentStatus.SKIPPED]:
            return False
        
        self.status = AssignmentStatus.SKIPPED
        self.completed_at = datetime.now().isoformat()
        self._modified = True
        
        if not self.save():
            return False
        
        # Update parent cycle status
        self._update_cycle_status()
        
        return True
    
    def _update_cycle_status(self) -> None:
        """Update the parent cycle status."""
        # To be implemented in subclasses
        pass
    
    def save(self) -> bool:
        """Save changes to database."""
        # To be implemented in subclasses
        raise NotImplementedError("Subclasses must implement save method")

Parameters

Name Type Default Kind
bases - -

Parameter Details

data: Optional dictionary containing assignment data. If provided, initializes the assignment with existing data. If None or missing required fields (UID, assigned_at, status), default values are automatically generated: a new UUID for UID, current ISO timestamp for assigned_at, and AssignmentStatus.PENDING for status. The dictionary can contain any of the following keys: UID, status, role, order, assigned_at, started_at, completed_at, due_date, user_uid, user_name, decision, comment.

Return Value

Instantiation returns an AssignmentBase object (or subclass instance) with initialized internal state. Key method returns: uid/status/role/order/assigned_at/user_uid/user_name/comment properties return strings; started_at/completed_at/due_date/decision properties return Optional[str]; get_user() returns DocUser object or None; notify_assignment() returns bool (False in base class); is_overdue() returns bool; start_assignment()/complete_assignment()/skip_assignment() return bool indicating success; save() raises NotImplementedError in base class.

Class Interface

Methods

__init__(self, data=None)

Purpose: Initialize assignment with optional data dictionary, setting defaults for UID, assigned_at, and status if not provided

Parameters:

  • data: Optional dictionary containing assignment data fields

Returns: None (constructor)

@property uid(self) -> str property

Purpose: Get the unique identifier for this assignment

Returns: String UID, empty string if not set

@property status(self) -> str property

Purpose: Get the current status of the assignment

Returns: String status value (PENDING, IN_PROGRESS, COMPLETED, REJECTED, SKIPPED)

@status.setter status(self, value: str) -> None property

Purpose: Set the assignment status and mark as modified

Parameters:

  • value: New status value

Returns: None

@property role(self) -> str property

Purpose: Get the role associated with this assignment

Returns: String role identifier, empty string if not set

@role.setter role(self, value: str) -> None property

Purpose: Set the assignment role and mark as modified

Parameters:

  • value: Role identifier

Returns: None

@property order(self) -> str property

Purpose: Get the order/sequence number of this assignment in a workflow

Returns: String order value, empty string if not set

@order.setter order(self, value: str) -> None property

Purpose: Set the assignment order and mark as modified

Parameters:

  • value: Order/sequence value

Returns: None

@property assigned_at(self) -> str property

Purpose: Get the timestamp when the assignment was created

Returns: ISO format timestamp string, empty string if not set

@property started_at(self) -> Optional[str] property

Purpose: Get the timestamp when work on the assignment started

Returns: ISO format timestamp string or None if not started

@started_at.setter started_at(self, value: Optional[str]) -> None property

Purpose: Set the start timestamp and mark as modified

Parameters:

  • value: ISO format timestamp or None

Returns: None

@property completed_at(self) -> Optional[str] property

Purpose: Get the timestamp when the assignment was completed

Returns: ISO format timestamp string or None if not completed

@completed_at.setter completed_at(self, value: Optional[str]) -> None property

Purpose: Set the completion timestamp and mark as modified

Parameters:

  • value: ISO format timestamp or None

Returns: None

@property due_date(self) -> Optional[str] property

Purpose: Get the due date for this assignment

Returns: ISO format timestamp string or None if no due date

@due_date.setter due_date(self, value: Optional[str]) -> None property

Purpose: Set the due date and mark as modified

Parameters:

  • value: ISO format timestamp or None

Returns: None

@property user_uid(self) -> str property

Purpose: Get the UID of the user assigned to this assignment

Returns: String user UID, empty string if not set

@user_uid.setter user_uid(self, value: str) -> None property

Purpose: Set the assigned user UID and mark as modified

Parameters:

  • value: User UID

Returns: None

@property user_name(self) -> str property

Purpose: Get the name of the user assigned to this assignment

Returns: String user name, empty string if not set

@user_name.setter user_name(self, value: str) -> None property

Purpose: Set the assigned user name and mark as modified

Parameters:

  • value: User name

Returns: None

@property decision(self) -> Optional[str] property

Purpose: Get the decision made on this assignment

Returns: String decision value or None if no decision made

@decision.setter decision(self, value: Optional[str]) -> None property

Purpose: Set the assignment decision and mark as modified

Parameters:

  • value: Decision value or None

Returns: None

@property comment(self) -> str property

Purpose: Get the comment associated with this assignment

Returns: String comment, empty string if not set

@comment.setter comment(self, value: str) -> None property

Purpose: Set the assignment comment and mark as modified

Parameters:

  • value: Comment text

Returns: None

get_user(self)

Purpose: Retrieve the DocUser object for the assigned user

Returns: DocUser object if user_uid is set and user exists, None otherwise

notify_assignment(self) -> bool

Purpose: Send notification to the assigned user about this assignment (to be implemented in subclasses)

Returns: Boolean indicating success (always False in base class)

is_overdue(self) -> bool

Purpose: Check if the assignment is past its due date and not yet completed

Returns: Boolean True if overdue (has due_date, past current time, and status is not completed/rejected/skipped), False otherwise

start_assignment(self) -> bool

Purpose: Transition assignment from PENDING to IN_PROGRESS status and set started_at timestamp

Returns: Boolean True if successfully started and saved, False if not in PENDING status or save failed

complete_assignment(self, approve: bool = True) -> bool

Purpose: Complete the assignment with approval or rejection, setting status and completed_at timestamp

Parameters:

  • approve: Boolean indicating whether to approve (True, sets COMPLETED status) or reject (False, sets REJECTED status)

Returns: Boolean True if successfully completed and saved, False if not in PENDING/IN_PROGRESS status or save failed

skip_assignment(self) -> bool

Purpose: Mark the assignment as skipped, setting SKIPPED status and completed_at timestamp

Returns: Boolean True if successfully skipped and saved, False if already completed/rejected/skipped or save failed

_update_cycle_status(self) -> None

Purpose: Update the parent workflow cycle status after assignment completion (to be implemented in subclasses)

Returns: None

save(self) -> bool

Purpose: Persist assignment changes to database (must be implemented in subclasses)

Returns: Boolean indicating save success (raises NotImplementedError in base class)

Attributes

Name Type Description Scope
_data Dict[str, Any] Internal dictionary storing all assignment data fields including UID, status, timestamps, user info, decision, and comment instance
_modified bool Flag indicating whether the assignment data has been modified since last save, automatically set to True when any property is changed instance

Dependencies

  • typing
  • datetime
  • enum
  • uuid
  • logging
  • CDocs.db.db_operations
  • CDocs.db.schema_manager
  • CDocs.config
  • CDocs.models.user_extensions
  • CDocs.models.document

Required Imports

from typing import Optional
from datetime import datetime
import uuid

Conditional/Optional Imports

These imports are only needed under specific conditions:

from CDocs.models.user_extensions import DocUser

Condition: only when calling get_user() method to retrieve user objects

Optional
from CDocs.db import db_operations as db

Condition: required by subclasses for database operations

Optional
from CDocs.db.schema_manager import NodeLabels, RelTypes

Condition: required by subclasses for database schema definitions

Optional

Usage Example

# Assuming ReviewerAssignment is a subclass that implements save()
from datetime import datetime, timedelta

# Create new assignment
assignment = ReviewerAssignment()
assignment.user_uid = 'user-123'
assignment.user_name = 'John Doe'
assignment.role = 'technical_reviewer'
assignment.order = '1'
assignment.due_date = (datetime.now() + timedelta(days=7)).isoformat()
assignment.save()

# Load existing assignment
existing_data = {'UID': 'abc-123', 'status': 'PENDING', 'user_uid': 'user-456'}
assignment = ReviewerAssignment(data=existing_data)

# Start working on assignment
if assignment.start_assignment():
    print(f'Started at: {assignment.started_at}')

# Add decision and complete
assignment.decision = 'APPROVED'
assignment.comment = 'Looks good, approved'
if assignment.complete_assignment(approve=True):
    print(f'Completed at: {assignment.completed_at}')

# Check if overdue
if assignment.is_overdue():
    print('Assignment is overdue!')

# Get assigned user
user = assignment.get_user()
if user:
    print(f'Assigned to: {user.name}')

Best Practices

  • Always call save() after modifying properties to persist changes to the database
  • Check return values from lifecycle methods (start_assignment, complete_assignment, skip_assignment) to ensure operations succeeded
  • Use the _modified flag to track whether changes need to be saved
  • Subclasses must implement the save() method for persistence
  • Subclasses should implement _update_cycle_status() to integrate with parent workflow cycles
  • Subclasses should override notify_assignment() to provide actual notification functionality
  • Use is_overdue() to check assignment status before allowing operations
  • Status transitions are enforced: PENDING -> IN_PROGRESS -> COMPLETED/REJECTED, or PENDING/IN_PROGRESS -> SKIPPED
  • Timestamps are automatically managed in ISO format for consistency
  • The UID is automatically generated if not provided, ensuring unique identification
  • Use properties for all data access to maintain the _modified flag correctly
  • Do not directly modify _data dictionary; use properties instead

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class ReviewerAssignment_v1 77.4% similar

    Model class representing a reviewer assignment within a review cycle, managing reviewer information, status, decisions, and lifecycle tracking for document review processes.

    From: /tf/active/vicechatdev/CDocs/models/review.py
  • class ApproverAssignment_v1 75.6% similar

    Model class representing an approver assignment within an approval cycle, managing the relationship between an approver and their approval task including status, decisions, and lifecycle tracking.

    From: /tf/active/vicechatdev/CDocs/models/approval_bis.py
  • class ReviewerAssignment 75.5% similar

    Model class representing a reviewer assignment within a review cycle, managing reviewer information, status, decisions, and lifecycle of review assignments.

    From: /tf/active/vicechatdev/CDocs single class/models/review.py
  • class ApproverAssignment 75.2% similar

    Model class representing an approver assignment within an approval cycle, managing the state and lifecycle of individual approval tasks assigned to users.

    From: /tf/active/vicechatdev/CDocs single class/models/approval.py
  • class ApproverAssignment_v1 74.2% similar

    Model class representing an approver assignment within an approval cycle, managing the relationship between an approver and their approval task including status, decisions, and timeline tracking.

    From: /tf/active/vicechatdev/CDocs/models/approval.py
← Back to Browse