class AssignmentBase
Base class for managing assignment lifecycle in a document review/approval workflow system, tracking status, timestamps, user assignments, and decisions.
/tf/active/vicechatdev/CDocs single class/models/workflow_base.py
315 - 528
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
typingdatetimeenumuuidloggingCDocs.db.db_operationsCDocs.db.schema_managerCDocs.configCDocs.models.user_extensionsCDocs.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
Optionalfrom CDocs.db import db_operations as db
Condition: required by subclasses for database operations
Optionalfrom CDocs.db.schema_manager import NodeLabels, RelTypes
Condition: required by subclasses for database schema definitions
OptionalUsage 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
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class ReviewerAssignment_v1 77.4% similar
-
class ApproverAssignment_v1 75.6% similar
-
class ReviewerAssignment 75.5% similar
-
class ApproverAssignment 75.2% similar
-
class ApproverAssignment_v1 74.2% similar