function create_document_legacy
Creates a new controlled document in a document management system with versioning, audit trails, and notifications. Generates document nodes in a graph database with relationships to users and versions.
/tf/active/vicechatdev/CDocs/controllers/document_controller.py
74 - 268
complex
Purpose
This function is the primary entry point for creating controlled documents in the CDocs system. It handles document creation with full lifecycle management including: generating unique document numbers, creating initial document versions, establishing relationships in a Neo4j graph database, logging audit trails, sending notifications, and managing permissions. It's designed for enterprise document control systems requiring compliance, traceability, and approval workflows.
Source Code
def create_document_legacy(
user: DocUser,
title: str,
doc_type: str,
department: str,
status: str = 'DRAFT',
doc_text: str = '',
doc_number: Optional[str] = None,
revision: str = '0.1',
effective_date: Optional[str] = None,
review_date: Optional[str] = None,
is_public: bool = False,
metadata: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
"""Create a new controlled document."""
try:
logger = logging.getLogger('CDocs.controllers.document_controller')
logger.info(f"Creating document: {title}, Type: {doc_type}")
# Import schema constants
from CDocs.db.schema_manager import NodeLabels, RelTypes
# Normalize document type to uppercase if it's a string
if isinstance(doc_type, str):
doc_type = doc_type.upper()
# Prepare additional properties
properties = {
'UID': str(uuid.uuid4()), # Generate UID here
'status': status,
'revision': revision,
'isPublic': is_public,
'createdDate': datetime.now(),
'modifiedDate': datetime.now(),
'title': title,
'docType': doc_type,
'department': department,
}
# Set creator and owner information
if hasattr(user, 'UID'):
properties['creatorUID'] = user.uid
properties['ownerUID'] = user.uid
if hasattr(user, 'name'):
properties['creatorName'] = user.name
properties['ownerName'] = user.name
# Add doc_number if provided, otherwise it will be generated later
if doc_number:
properties['docNumber'] = doc_number
else:
# Generate a document number
try:
from ..config import settings
if hasattr(settings, 'generate_document_number'):
properties['docNumber'] = settings.generate_document_number(doc_type, department)
else:
# Simple fallback document number generation
prefix = doc_type[:3] if doc_type else "DOC"
dept_code = department[:3] if department else "GEN"
import random
properties['docNumber'] = f"{prefix}-{dept_code}-{random.randint(1000, 9999)}"
except Exception as e:
logger.warning(f"Error generating document number: {e}")
# Simple fallback
import random
properties['docNumber'] = f"DOC-{random.randint(10000, 99999)}"
# Add dates if provided
if effective_date:
properties['effectiveDate'] = effective_date
if review_date:
properties['reviewDate'] = review_date
# Add metadata if provided
if metadata:
properties['metadata'] = metadata
# Create the document node
logger.debug(f"Creating document node with properties: {properties}")
doc_data = db.create_node(NodeLabels.CONTROLLED_DOCUMENT, properties)
if not doc_data:
raise BusinessRuleError("Failed to create document in database")
# Find CDocs root node and create relationship
cdocs_result = db.run_query("MATCH (c:CDocs) RETURN c.UID as uid LIMIT 1")
if cdocs_result and 'uid' in cdocs_result[0]:
cdocs_uid = cdocs_result[0]['uid']
# Create relationship between CDocs root and document
db.create_relationship(
cdocs_uid,
doc_data['UID'],
RelTypes.HAS_DOCUMENT # Now we know this is defined in RelTypes
)
logger.debug(f"Created relationship from CDocs root to document: {doc_data['UID']}")
else:
logger.warning("CDocs root node not found. Document created without relationship.")
# Now create a document object properly with the node data (not just the UID)
document = ControlledDocument(doc_data)
# If document content is provided, create an initial version
if doc_text:
try:
# Create version properties
version_props = {
'UID': str(uuid.uuid4()), # Generate UID here
'versionNumber': revision,
'content': doc_text,
'status': status,
'createdDate': datetime.now(),
'comment': 'Initial version'
}
# Add creator info if available
if hasattr(user, 'UID'):
version_props['creatorUID'] = user.uid
if hasattr(user, 'name'):
version_props['creatorName'] = user.name
# Create the version node
version_data = db.create_node(NodeLabels.DOCUMENT_VERSION, version_props)
if version_data:
# Create relationship from document to version
db.create_relationship(
doc_data['UID'],
version_data['UID'],
RelTypes.HAS_VERSION
)
# Create relationship for current version
db.create_relationship(
doc_data['UID'],
version_data['UID'],
RelTypes.CURRENT_VERSION
)
# Update document with current version UID
db.update_node(
doc_data['UID'],
{'currentVersionUID': version_data['UID']}
)
logger.debug(f"Created initial version for document: {doc_data['UID']}")
except Exception as e:
logger.error(f"Error creating initial version: {e}")
# Continue anyway, document created without initial version
# Log document creation event
audit_trail.log_document_lifecycle_event(
event_type="DOCUMENT_CREATED",
user=user,
document_uid=document.uid,
details={"title": title, "doc_type": doc_type, "department": department}
)
if document:
# Create notification for document owner
notification_manager = NotificationManager()
if hasattr(user, 'uid'):
notification_manager.create_notification(
notification_type='DOCUMENT_CREATED',
user_uid=user.uid,
resource_uid=document.uid,
resource_type='DOCUMENT',
message=f"Document {document.doc_number} created successfully",
details={
'doc_number': document.doc_number,
'title': title,
'doc_type': doc_type,
'department': department
}
)
# Send notification if configured
notifications.notify_document_update(document, "DOCUMENT_CREATED")
# Return result with document information
return {
"success": True,
"document": document.to_dict(),
"message": f"Document {document.doc_number} created successfully"
}
except Exception as e:
logger.error(f"Error creating document: {e}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
raise BusinessRuleError(f"Failed to create document: {e}")
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
user |
DocUser | - | positional_or_keyword |
title |
str | - | positional_or_keyword |
doc_type |
str | - | positional_or_keyword |
department |
str | - | positional_or_keyword |
status |
str | 'DRAFT' | positional_or_keyword |
doc_text |
str | '' | positional_or_keyword |
doc_number |
Optional[str] | None | positional_or_keyword |
revision |
str | '0.1' | positional_or_keyword |
effective_date |
Optional[str] | None | positional_or_keyword |
review_date |
Optional[str] | None | positional_or_keyword |
is_public |
bool | False | positional_or_keyword |
metadata |
Optional[Dict[str, Any]] | None | positional_or_keyword |
Parameter Details
user: DocUser object representing the authenticated user creating the document. Must have UID and name attributes. This user becomes the document creator and owner.
title: String containing the document title. Used for display and search purposes.
doc_type: String specifying the document type (e.g., 'SOP', 'POLICY', 'PROCEDURE'). Will be normalized to uppercase. Used for document categorization and number generation.
department: String identifying the department owning the document. Used for organization and document number generation.
status: Optional string for document status. Defaults to 'DRAFT'. Common values include 'DRAFT', 'IN_REVIEW', 'APPROVED', 'PUBLISHED', 'EFFECTIVE', 'ARCHIVED', 'OBSOLETE'.
doc_text: Optional string containing the initial document content. If provided, creates an initial document version with this content.
doc_number: Optional string for explicit document number. If not provided, system generates one automatically using doc_type and department.
revision: Optional string for initial revision number. Defaults to '0.1'. Used for version tracking.
effective_date: Optional string representing when the document becomes effective. Format should match system date format.
review_date: Optional string representing when the document should be reviewed next. Format should match system date format.
is_public: Optional boolean indicating if document is publicly accessible. Defaults to False for controlled access.
metadata: Optional dictionary containing additional custom metadata fields to store with the document.
Return Value
Type: Dict[str, Any]
Returns a dictionary with three keys: 'success' (boolean indicating operation success), 'document' (dictionary representation of the created ControlledDocument object including UID, doc_number, title, status, dates, and all properties), and 'message' (string with success message including the generated document number). On error, raises BusinessRuleError exception.
Dependencies
logginguuiddatetimerandomtracebackCDocs.dbCDocs.config.settingsCDocs.models.document.ControlledDocumentCDocs.models.user_extensions.DocUserCDocs.utils.audit_trailCDocs.utils.notificationsCDocs.utils.notifications.NotificationManagerCDocs.db.schema_manager.NodeLabelsCDocs.db.schema_manager.RelTypesCDocs.controllers.BusinessRuleError
Required Imports
import logging
import uuid
from datetime import datetime
from typing import Dict, Any, Optional
from CDocs import db
from CDocs.config import settings
from CDocs.models.document import ControlledDocument
from CDocs.models.user_extensions import DocUser
from CDocs.utils import audit_trail
from CDocs.utils import notifications
from CDocs.utils.notifications import NotificationManager
from CDocs.db.schema_manager import NodeLabels, RelTypes
from CDocs.controllers import BusinessRuleError
Conditional/Optional Imports
These imports are only needed under specific conditions:
import random
Condition: Used for fallback document number generation when settings.generate_document_number is not available
Required (conditional)from CDocs.config import settings
Condition: Imported inside function for document number generation if settings.generate_document_number method exists
OptionalUsage Example
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.document_controller import create_document_legacy
from datetime import datetime, timedelta
# Create user object
user = DocUser({'UID': 'user-123', 'name': 'John Doe'})
# Create a simple document
result = create_document_legacy(
user=user,
title='Quality Management Procedure',
doc_type='SOP',
department='Quality',
status='DRAFT'
)
print(f"Document created: {result['document']['docNumber']}")
print(f"Document UID: {result['document']['UID']}")
# Create document with content and metadata
result = create_document_legacy(
user=user,
title='Safety Protocol',
doc_type='POLICY',
department='Safety',
status='DRAFT',
doc_text='This is the initial safety protocol content...',
doc_number='POL-SAF-1001',
revision='1.0',
effective_date='2024-01-01',
review_date='2025-01-01',
is_public=False,
metadata={'category': 'safety', 'priority': 'high'}
)
if result['success']:
doc = result['document']
print(f"Created: {doc['title']} ({doc['docNumber']})")
Best Practices
- Always provide a valid DocUser object with UID and name attributes
- Use uppercase for doc_type values for consistency (function normalizes automatically)
- Provide doc_number explicitly if you need specific numbering schemes, otherwise let system generate
- Include doc_text parameter to create initial version automatically, avoiding separate version creation
- Handle BusinessRuleError exceptions to catch document creation failures
- Ensure CDocs root node exists in database before calling this function
- Use appropriate status values from document_status module constants
- Provide review_date for documents requiring periodic review
- Set is_public=False for sensitive controlled documents
- Use metadata parameter for custom fields rather than modifying core properties
- Function is decorated with transaction, so database changes rollback on error
- Function requires CREATE_DOCUMENT permission, ensure user has proper authorization
- Function logs audit trail automatically, no need for manual logging
- Notifications are sent automatically to document owner
- Document number generation uses doc_type and department, ensure these are meaningful
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function create_document 94.0% similar
-
function create_controlled_document 81.2% similar
-
function create_document_v3 74.2% similar
-
function create_document_v4 72.3% similar
-
function create_document_v2 68.1% similar