function archive_document
Archives a controlled document by changing its status to ARCHIVED, ensuring a PDF version exists and logging the action with audit trail and notifications.
/tf/active/vicechatdev/document_controller_backup.py
1442 - 1542
moderate
Purpose
This function manages the document archiving workflow in a controlled document management system. It validates that documents can only be archived from PUBLISHED or EFFECTIVE status, ensures PDF versions exist for compliance, updates document metadata with archive information, logs the lifecycle event, and notifies stakeholders. It enforces business rules around document lifecycle management and maintains audit trails for regulatory compliance.
Source Code
def archive_document(
user: DocUser,
document_uid: str,
archive_reason: str,
archive_comment: Optional[str] = None
) -> Dict[str, Any]:
"""
Archive a document, changing its status to ARCHIVED.
Ensures the document is available in PDF format.
Args:
user: User archiving the document
document_uid: UID of document to archive
archive_reason: Reason for archiving
archive_comment: Optional comment about archiving
Returns:
Dictionary with archive status
Raises:
ResourceNotFoundError: If document not found
ValidationError: If validation fails
PermissionError: If user doesn't have permission
BusinessRuleError: If archiving is not allowed
"""
try:
# Get document instance
document = ControlledDocument(uid=document_uid)
if not document:
raise ResourceNotFoundError(f"Document not found: {document_uid}")
# Check if document can be archived
if document.status not in [STATUS_PUBLISHED, STATUS_EFFECTIVE]:
raise BusinessRuleError(f"Cannot archive document with status {document.status}")
# Validate archive reason
if not archive_reason:
raise ValidationError("Archive reason is required")
# Check if current version has a PDF version
current_version = document.current_version
if not current_version:
raise BusinessRuleError("Document has no current version")
if not current_version.pdf_file_path:
raise BusinessRuleError("Document must have a PDF version before archiving")
# Store previous status for audit
previous_status = document.status
# Update document
document.status = STATUS_ARCHIVED
# Add archive info to metadata
document_metadata = {
'archived_by': user.username,
'archived_date': datetime.now().isoformat(),
'archive_reason': archive_reason,
'archive_comment': archive_comment
}
# Update document in database
db.update_node(document_uid, {
'status': STATUS_ARCHIVED,
'modifiedDate': datetime.now(),
'metadata': document_metadata
})
# Log archive event
audit_trail.log_document_lifecycle_event(
event_type="DOCUMENT_ARCHIVED",
user=user,
document_uid=document_uid,
details={
"previous_status": previous_status,
"archive_reason": archive_reason,
"archive_comment": archive_comment
}
)
# Notify about archiving
notifications.notify_document_update(document, "DOCUMENT_STATUS_CHANGED")
return {
"success": True,
"document_uid": document_uid,
"document_number": document.doc_number,
"title": document.title,
"previous_status": previous_status,
"new_status": STATUS_ARCHIVED,
"archive_reason": archive_reason,
"archive_comment": archive_comment,
"message": f"Document {document.doc_number} archived successfully"
}
except (ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError) as e:
# Re-raise known errors
raise
except Exception as e:
logger.error(f"Error archiving document {document_uid}: {e}")
raise BusinessRuleError(f"Failed to archive document: {e}")
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
user |
DocUser | - | positional_or_keyword |
document_uid |
str | - | positional_or_keyword |
archive_reason |
str | - | positional_or_keyword |
archive_comment |
Optional[str] | None | positional_or_keyword |
Parameter Details
user: DocUser object representing the authenticated user performing the archive action. Used for permission checks, audit logging, and tracking who archived the document.
document_uid: String containing the unique identifier (UID) of the document to be archived. Must correspond to an existing ControlledDocument in the database.
archive_reason: Required string explaining why the document is being archived. Cannot be empty. Used for audit trail and compliance documentation.
archive_comment: Optional string providing additional context or notes about the archiving action. Can be None. Stored in document metadata for future reference.
Return Value
Type: Dict[str, Any]
Returns a dictionary containing archive operation results with keys: 'success' (bool indicating operation success), 'document_uid' (str), 'document_number' (str), 'title' (str), 'previous_status' (str showing status before archiving), 'new_status' (str showing STATUS_ARCHIVED), 'archive_reason' (str), 'archive_comment' (str or None), and 'message' (str with success message). On error, raises one of the documented exceptions instead of returning.
Dependencies
logginguuidostempfiletypingdatetimeiopanelshutiltracebackCDocs
Required Imports
from typing import Dict, Any, Optional
from datetime import datetime
from CDocs import db
from CDocs.models.document import ControlledDocument
from CDocs.models.user_extensions import DocUser
from CDocs.utils import notifications
from CDocs.utils import audit_trail
from CDocs.controllers import require_permission, log_controller_action, transaction
from CDocs.controllers import ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError
from CDocs.models.document_status import STATUS_PUBLISHED, STATUS_EFFECTIVE, STATUS_ARCHIVED
import logging
Usage Example
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.document_controller import archive_document
from CDocs.controllers import ResourceNotFoundError, BusinessRuleError
# Assume user is authenticated
user = DocUser(username='john.doe')
document_uid = 'doc-12345-abcde'
archive_reason = 'Superseded by newer version'
archive_comment = 'Document replaced by DOC-2024-001'
try:
result = archive_document(
user=user,
document_uid=document_uid,
archive_reason=archive_reason,
archive_comment=archive_comment
)
if result['success']:
print(f"Document {result['document_number']} archived successfully")
print(f"Previous status: {result['previous_status']}")
print(f"New status: {result['new_status']}")
print(f"Reason: {result['archive_reason']}")
except ResourceNotFoundError as e:
print(f"Document not found: {e}")
except BusinessRuleError as e:
print(f"Cannot archive document: {e}")
except PermissionError as e:
print(f"Permission denied: {e}")
Best Practices
- Always ensure the user has ARCHIVE_DOCUMENT permission before calling this function (handled by decorator)
- Provide meaningful archive_reason values for audit compliance and future reference
- Only call this function on documents with STATUS_PUBLISHED or STATUS_EFFECTIVE status
- Ensure documents have PDF versions generated before attempting to archive
- Handle all four exception types (ResourceNotFoundError, ValidationError, PermissionError, BusinessRuleError) in calling code
- The function is wrapped in a transaction decorator, so database changes will be rolled back on error
- Archive operations are logged automatically via log_controller_action decorator
- Consider the notification side effects - stakeholders will be notified of the status change
- Archive metadata is stored permanently in the document for compliance and audit purposes
- Do not attempt to archive documents in DRAFT, IN_REVIEW, or other non-published states
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function delete_document 70.8% similar
-
function publish_document 70.8% similar
-
function update_document 63.9% similar
-
function get_document 63.2% similar
-
function download_document_version 60.0% similar