function create_document_version
Creates a new controlled document in a document management system with versioning, audit trails, and relationship management in a Neo4j graph database.
/tf/active/vicechatdev/CDocs copy/controllers/document_controller.py
47 - 223
complex
Purpose
This function serves as the primary entry point for creating controlled documents in the CDocs system. It handles document creation with full lifecycle management including: generating unique identifiers, establishing relationships with the CDocs root node, creating initial document versions with content, setting up ownership and permissions, generating document numbers, logging audit trails, and sending notifications. The function is designed for enterprise document control systems requiring compliance, traceability, and version management.
Source Code
def create_document(
user: DocUser,
title: str,
doc_type: str,
department: str,
status: str = 'DRAFT',
doc_text: str = '',
doc_number: Optional[str] = None,
revision: str = '1.0',
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 CDocs.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}
)
# 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 | '1.0' | 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. Used for setting creator/owner information and audit logging.
title: String containing the document title. Required field that will be stored as the document's display name.
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 or organizational unit owning the document. Used for access control and document number generation.
status: String indicating document status. Defaults to 'DRAFT'. Common values include 'DRAFT', 'PENDING_REVIEW', 'APPROVED', 'OBSOLETE'.
doc_text: String containing the initial document content/body. If provided, creates an initial version node. Empty string by default.
doc_number: Optional string for manually specifying the document number. If None, a document number will be auto-generated using doc_type and department codes.
revision: String representing the document revision number. Defaults to '1.0'. Used for version tracking.
effective_date: Optional string (or datetime) specifying when the document becomes effective. Format should match system date format.
review_date: Optional string (or datetime) specifying when the document should be reviewed next. Used for compliance and lifecycle management.
is_public: Boolean flag indicating if the document is publicly accessible. Defaults to False for restricted access.
metadata: Optional dictionary containing additional custom metadata fields as key-value pairs. Stored with the document node for extensibility.
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 containing all document properties including UID, docNumber, title, status, dates, etc.), and 'message' (string with human-readable success message including the generated document number). Raises BusinessRuleError exception on failure.
Dependencies
logginguuidostempfiletypingdatetimeiopaneltracebackrandom
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.db.schema_manager import NodeLabels, RelTypes
from CDocs.controllers import require_permission, log_controller_action, transaction
from CDocs.controllers import BusinessRuleError
Conditional/Optional Imports
These imports are only needed under specific conditions:
from CDocs.config import settings
Condition: imported inside function for document number generation if settings.generate_document_number exists
Optionalimport random
Condition: imported inside function as fallback for document number generation when settings method is unavailable
Required (conditional)import traceback
Condition: imported inside exception handler for detailed error logging
Required (conditional)Usage Example
from CDocs.models.user_extensions import DocUser
from CDocs.controllers.document_controller import create_document
from datetime import datetime, timedelta
# Create user object
user = DocUser(uid='user-123', name='John Doe')
# Create a new document
result = create_document(
user=user,
title='Quality Management System Procedure',
doc_type='SOP',
department='Quality',
status='DRAFT',
doc_text='This document describes the quality management procedures...',
revision='1.0',
effective_date=datetime.now().isoformat(),
review_date=(datetime.now() + timedelta(days=365)).isoformat(),
is_public=False,
metadata={'category': 'QMS', 'priority': 'high'}
)
if result['success']:
doc = result['document']
print(f"Document created: {doc['docNumber']}")
print(f"UID: {doc['UID']}")
print(f"Message: {result['message']}")
Best Practices
- Always pass a valid DocUser object with UID and name attributes to ensure proper audit trails
- Use meaningful document types and departments as they affect document number generation and categorization
- Provide doc_text during creation to establish an initial version; otherwise, the document will exist without content
- Handle BusinessRuleError exceptions to catch database failures or validation errors
- Ensure the CDocs root node exists in the database before calling this function
- Use ISO format strings for effective_date and review_date for consistency
- The function is decorated with @transaction, so database operations are atomic and will rollback on error
- The function requires 'CREATE_DOCUMENT' permission, so ensure users have appropriate permissions configured
- Document numbers are auto-generated if not provided; manual doc_numbers should follow organizational conventions
- The function logs extensively; configure logging appropriately for production environments
- Metadata dictionary allows extensibility but should follow a consistent schema within your organization
- The function creates multiple nodes (document, version) and relationships; ensure database performance is adequate for your scale
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function create_document 94.5% similar
-
function create_document_legacy 93.5% similar
-
function create_controlled_document 79.6% similar
-
class ControlledDocument 77.8% similar
-
function create_document_version_v1 75.2% similar