🔍 Code Extractor

function create_document

Maturity: 85

Creates a new controlled document in a document management system with versioning, audit trails, and optional initial content.

File:
/tf/active/vicechatdev/document_controller_backup.py
Lines:
65 - 241
Complexity:
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 in a graph database (Neo4j), creating initial document versions, logging audit events, and sending notifications. The function enforces permissions, validates inputs, and ensures transactional integrity through decorators.

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 ..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 permission checks, audit logging, and setting document ownership.

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., 'POLICY', 'PROCEDURE', 'FORM'). 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 representing the document lifecycle status. Defaults to 'DRAFT'. Common values include 'DRAFT', 'IN_REVIEW', 'APPROVED', 'PUBLISHED', 'EFFECTIVE', 'ARCHIVED', 'OBSOLETE'.

doc_text: String containing the initial document content/body. If provided, creates an initial document version. 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 (ISO format recommended) specifying when the document becomes effective. Stored as-is without validation.

review_date: Optional string (ISO format recommended) specifying when the document should be reviewed next. Used for compliance tracking.

is_public: Boolean flag indicating whether the document is publicly accessible. Defaults to False for restricted access.

metadata: Optional dictionary containing additional custom metadata fields. Stored as-is on the document node.

Return Value

Type: Dict[str, Any]

Returns a dictionary with three keys: 'success' (boolean, always True on successful execution), 'document' (dictionary containing the full document data from document.to_dict() including UID, docNumber, title, status, dates, etc.), and 'message' (string with success confirmation including the generated document number). On error, raises BusinessRuleError exception instead of returning.

Dependencies

  • logging
  • uuid
  • os
  • tempfile
  • typing
  • datetime
  • io
  • panel
  • shutil
  • traceback
  • random

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 notifications
from CDocs.utils import audit_trail
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.db.schema_manager import NodeLabels, RelTypes

Condition: imported inside function body for schema constants

Required (conditional)
from ..config import settings

Condition: imported inside try block for document number generation if settings.generate_document_number exists

Optional
import random

Condition: imported inside exception handler for fallback document number generation

Required (conditional)

Usage Example

from CDocs.models.user_extensions import DocUser
from CDocs.controllers.document_controller import create_document

# Create a user object (typically from authentication)
user = DocUser({'UID': 'user-123', 'name': 'John Doe'})

# Create a simple document
result = create_document(
    user=user,
    title='Quality Management Policy',
    doc_type='POLICY',
    department='Quality Assurance',
    status='DRAFT'
)

print(f"Document created: {result['document']['docNumber']}")
print(f"Document UID: {result['document']['UID']}")

# Create a document with initial content and metadata
result = create_document(
    user=user,
    title='Standard Operating Procedure',
    doc_type='SOP',
    department='Manufacturing',
    status='DRAFT',
    doc_text='This is the initial content of the SOP...',
    doc_number='SOP-MFG-2024-001',
    revision='1.0',
    effective_date='2024-12-01',
    review_date='2025-12-01',
    is_public=False,
    metadata={'category': 'production', 'priority': 'high'}
)

if result['success']:
    doc = result['document']
    print(f"Created: {doc['title']} ({doc['docNumber']})")

Best Practices

  • Always pass a valid DocUser object with UID and name attributes for proper audit trails
  • Use uppercase constants for doc_type (e.g., 'POLICY', 'SOP', 'PROCEDURE') for consistency
  • Provide doc_text during creation to establish an initial version, otherwise the document will have no content
  • Handle BusinessRuleError exceptions when calling this function as it raises on any failure
  • Ensure the CDocs root node exists in the database before calling this function
  • Use ISO 8601 format for effective_date and review_date for consistency
  • The function is decorated with @transaction, so database operations are atomic
  • The function is decorated with @require_permission('CREATE_DOCUMENT'), ensure user has this permission
  • Document numbers are auto-generated if not provided, but custom numbers can be specified for migration scenarios
  • The function creates relationships in Neo4j: CDocs->HAS_DOCUMENT->Document and Document->HAS_VERSION->Version
  • Notifications are sent automatically on document creation if the notifications system is configured
  • All document creation events are logged to the audit trail automatically
  • The function sets both creatorUID/creatorName and ownerUID/ownerName to the same user initially

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function create_document_v2 80.3% similar

    Creates a new controlled document in a document management system with specified properties, type, department, and status.

    From: /tf/active/vicechatdev/document_controller_backup.py
  • function create_document_v1 68.0% similar

    Creates a new version of an existing document in a document management system, storing the file in FileCloud and tracking version metadata in Neo4j graph database.

    From: /tf/active/vicechatdev/document_controller_backup.py
  • function clone_document 63.6% similar

    Clones an existing controlled document to create either a new independent document or a new revision of the same document, optionally including the document's content.

    From: /tf/active/vicechatdev/document_controller_backup.py
  • function delete_document 62.2% similar

    Deletes a controlled document from the system with permission checks, status validation, and audit logging.

    From: /tf/active/vicechatdev/document_controller_backup.py
  • function add_document_to_graph 61.9% similar

    Creates nodes and relationships in a Neo4j graph database for a processed document, including its text and table chunks, connecting it to a folder hierarchy.

    From: /tf/active/vicechatdev/offline_docstore_multi.py
← Back to Browse