function generate_document_number
Generates unique, sequential document numbers for a given document type and department using persistent counters stored in Neo4j database.
/tf/active/vicechatdev/CDocs/settings_prod.py
561 - 652
complex
Purpose
This function creates standardized document identifiers by maintaining atomic counters in a Neo4j graph database. It ensures unique document numbering across the system with support for yearly counter resets, custom formatting patterns, and fallback mechanisms. The function is designed for document management systems requiring persistent, collision-free document identification with department and type-based organization.
Source Code
def generate_document_number(doc_type: str, department: str) -> str:
"""
Generate a new document number based on type and department using persistent
counters stored in Neo4j.
Args:
doc_type: Document type code (e.g., 'SOP')
department: Department code (e.g., 'QA')
Returns:
Formatted document number string
"""
from CDocs.db import db_operations as db
from datetime import datetime
# Get document type info from config if available
doc_info = DOCUMENT_CONFIG.get(doc_type, {})
# If not found in config, use simple type name
prefix = doc_info.get('prefix', doc_type)
# Get current year
current_year = datetime.now().year
try:
# First, get the CDocs root node UID
cdocs_result = db.run_query(
"MATCH (c:CDocs) RETURN c.UID as uid LIMIT 1"
)
if not cdocs_result or not cdocs_result[0].get('uid'):
logger.error("Could not find CDocs root node")
# Fall back to in-memory counter as a last resort
return _generate_document_number_fallback(doc_type, department)
cdocs_uid = cdocs_result[0]['uid']
# Get or create counter with atomic increment using MERGE
result = db.run_query(
"""
MATCH (c:CDocs {UID: $cdocs_uid})
MERGE (c)-[:HAS_COUNTER]->(counter:DocumentCounter {department: $department, docType: $docType})
ON CREATE SET
counter.UID = randomUUID(),
counter.value = 1,
counter.currentYear = $current_year,
counter.createdDate = datetime()
ON MATCH SET
counter.value = CASE
WHEN $reset_yearly AND counter.currentYear < $current_year
THEN 1
ELSE counter.value + 1
END,
counter.currentYear = $current_year,
counter.lastUpdated = datetime()
RETURN counter.value as value
""",
{
"cdocs_uid": cdocs_uid,
"department": department,
"docType": doc_type,
"current_year": current_year,
"reset_yearly": DOCUMENT_NUMBERING.get('reset_counter_yearly', True)
}
)
if not result:
logger.error("Failed to get/update document counter")
return _generate_document_number_fallback(doc_type, department)
next_value = result[0]['value']
# Use document type specific numbering format if available, otherwise use default
numbering_format = doc_info.get('numbering_format',
DOCUMENT_NUMBERING.get('numbering_format',
'{prefix}-{dept}-{year}-{number:04d}'))
# Format document number
return numbering_format.format(
prefix=prefix,
dept=department,
year=current_year if DOCUMENT_NUMBERING.get('use_year_in_numbering', False) else "",
number=next_value
)
except Exception as e:
# Log the error
logger.error(f"Error generating document number: {e}")
import traceback
logger.error(traceback.format_exc())
# Fall back to in-memory counter
return _generate_document_number_fallback(doc_type, department)
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
doc_type |
str | - | positional_or_keyword |
department |
str | - | positional_or_keyword |
Parameter Details
doc_type: Document type code string (e.g., 'SOP', 'WI', 'FORM') that categorizes the document. This is used to look up configuration settings and determine the document number prefix. Expected to be a short alphanumeric code.
department: Department code string (e.g., 'QA', 'RD', 'MFG') identifying the organizational unit. Used in the document number format and as part of the counter key to maintain separate sequences per department.
Return Value
Type: str
Returns a formatted document number string following the pattern defined in configuration (default: '{prefix}-{dept}-{year}-{number:04d}'). Example outputs: 'SOP-QA-2024-0001', 'WI-MFG-0042'. If database operations fail, returns a fallback-generated number from an in-memory counter.
Dependencies
CDocs.db.db_operationsdatetimeloggingtraceback
Required Imports
from CDocs.db import db_operations as db
from datetime import datetime
import logging
import traceback
Conditional/Optional Imports
These imports are only needed under specific conditions:
from datetime import datetime
Condition: Always needed - imported inside function for getting current year
Required (conditional)import traceback
Condition: Only used in exception handling for detailed error logging
OptionalUsage Example
# Assuming proper configuration and database setup
from CDocs.config import DOCUMENT_CONFIG, DOCUMENT_NUMBERING
import logging
# Configure logger
logger = logging.getLogger(__name__)
# Define configuration
DOCUMENT_CONFIG = {
'SOP': {
'prefix': 'SOP',
'numbering_format': '{prefix}-{dept}-{year}-{number:04d}'
}
}
DOCUMENT_NUMBERING = {
'reset_counter_yearly': True,
'use_year_in_numbering': True,
'numbering_format': '{prefix}-{dept}-{year}-{number:04d}'
}
# Generate document number
doc_number = generate_document_number('SOP', 'QA')
print(doc_number) # Output: 'SOP-QA-2024-0001'
# Generate another for same type/dept
doc_number2 = generate_document_number('SOP', 'QA')
print(doc_number2) # Output: 'SOP-QA-2024-0002'
# Different department gets separate counter
doc_number3 = generate_document_number('SOP', 'RD')
print(doc_number3) # Output: 'SOP-RD-2024-0001'
Best Practices
- Ensure Neo4j database is properly initialized with a CDocs root node before calling this function
- Configure DOCUMENT_CONFIG and DOCUMENT_NUMBERING dictionaries before use to control numbering behavior
- Implement the _generate_document_number_fallback function as a safety mechanism for database failures
- Use consistent department and document type codes across your application to maintain organized counters
- The function uses MERGE with atomic operations to prevent race conditions in concurrent environments
- Monitor logger output for errors as the function falls back silently to in-memory counters on database failures
- Consider the yearly reset behavior when planning document archival and retrieval strategies
- Test the fallback mechanism to ensure continuity of operations during database outages
- The function creates DocumentCounter nodes with relationships to the CDocs root node - ensure proper database cleanup policies
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function generate_document_number_v1 85.4% similar
-
function get_next_document_number 85.2% similar
-
function _generate_document_number_fallback 73.9% similar
-
function validate_document_number 65.5% similar
-
function initialize_document_counters 63.8% similar