function generate_audit_report
Generates a comprehensive audit report for a controlled document by aggregating document metadata, version history, review cycles, approvals, and categorized audit events.
/tf/active/vicechatdev/CDocs/utils/audit_trail.py
716 - 825
complex
Purpose
This function creates a detailed audit trail report for compliance and tracking purposes in a document management system. It retrieves document information from a Neo4j graph database, including all versions, review cycles, approvals, and historical events. The report organizes events by category and provides counts and summaries useful for regulatory audits, compliance reviews, and document lifecycle tracking.
Source Code
def generate_audit_report(document_uid: str) -> Dict[str, Any]:
"""
Generate a comprehensive audit report for a document.
Args:
document_uid: UID of document
Returns:
Dictionary with audit report data
"""
try:
# Get document data
query = """
MATCH (d:ControlledDocument {UID: $doc_uid})
OPTIONAL MATCH (d)-[:HAS_VERSION]->(v:DocumentVersion)
OPTIONAL MATCH (d)-[:CURRENT_VERSION]->(cv:DocumentVersion)
RETURN d, count(v) as versionCount, cv
"""
doc_result = db.run_query(query, {"doc_uid": document_uid})
if not doc_result:
logger.error(f"Document not found: {document_uid}")
return {"error": "Document not found"}
document = doc_result[0]['d']
version_count = doc_result[0]['versionCount']
current_version = doc_result[0].get('cv')
# Get all history events
history = get_document_history(document_uid)
# Organize events by category
events_by_category = {}
for event in history:
category = event.get('eventCategory', 'OTHER')
if category not in events_by_category:
events_by_category[category] = []
events_by_category[category].append(event)
# Get review cycles
query = """
MATCH (d:ControlledDocument {UID: $doc_uid})-[:HAS_VERSION]->(v:DocumentVersion)
MATCH (v)-[:FOR_REVIEW]->(r:ReviewCycle)
OPTIONAL MATCH (r)-[:REVIEWED_BY]->(u:User)
RETURN r.UID as reviewUID, r.status as status, r.startDate as startDate,
r.completionDate as completionDate, count(u) as reviewerCount
ORDER BY r.startDate DESC
"""
review_result = db.run_query(query, {"doc_uid": document_uid})
reviews = [
{
'UID': record['reviewUID'],
'status': record['status'],
'startDate': record['startDate'],
'completionDate': record['completionDate'],
'reviewerCount': record['reviewerCount']
}
for record in review_result
]
# Get approvals
query = """
MATCH (d:ControlledDocument {UID: $doc_uid})-[:HAS_VERSION]->(v:DocumentVersion)
MATCH (v)-[:FOR_REVIEW]->(r:ReviewCycle)
MATCH (r)-[:FOR_APPROVAL]->(a:Approval)
OPTIONAL MATCH (a)-[:APPROVED_BY]->(u:User)
RETURN a.UID as approvalUID, a.status as status, a.startDate as startDate,
a.completionDate as completionDate, count(u) as approverCount
ORDER BY a.startDate DESC
"""
approval_result = db.run_query(query, {"doc_uid": document_uid})
approvals = [
{
'UID': record['approvalUID'],
'status': record['status'],
'startDate': record['startDate'],
'completionDate': record['completionDate'],
'approverCount': record['approverCount']
}
for record in approval_result
]
# Build full report
report = {
'document': {
'UID': document.get('UID'),
'docNumber': document.get('docNumber'),
'title': document.get('title'),
'status': document.get('status'),
'docType': document.get('docType'),
'department': document.get('department'),
'createdDate': document.get('createdDate')
},
'currentVersion': current_version,
'versionCount': version_count,
'reviews': reviews,
'approvals': approvals,
'eventCount': len(history),
'eventsByCategory': events_by_category,
'allEvents': history,
'reportGeneratedAt': datetime.now()
}
return report
except Exception as e:
logger.error(f"Error generating audit report: {e}")
return {"error": f"Error generating report: {e}"}
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
document_uid |
str | - | positional_or_keyword |
Parameter Details
document_uid: Unique identifier (UID) string for the controlled document. This should be a valid UID that exists in the Neo4j database as a ControlledDocument node. The function will return an error if the document is not found.
Return Value
Type: Dict[str, Any]
Returns a dictionary containing comprehensive audit report data. On success, includes keys: 'document' (metadata dict with UID, docNumber, title, status, docType, department, createdDate), 'currentVersion' (current DocumentVersion node data or None), 'versionCount' (integer count of versions), 'reviews' (list of review cycle dicts with UID, status, dates, reviewerCount), 'approvals' (list of approval dicts with UID, status, dates, approverCount), 'eventCount' (total number of audit events), 'eventsByCategory' (dict mapping category names to lists of events), 'allEvents' (complete list of all historical events), and 'reportGeneratedAt' (datetime of report generation). On error, returns a dict with single 'error' key containing error message string.
Dependencies
logginguuidtypingdatetimejsonCDocs.dbCDocs.configCDocs.db.schema_managerCDocs.models.user_extensions
Required Imports
from typing import Dict, Any
from datetime import datetime
import logging
from CDocs import db
Usage Example
from typing import Dict, Any
from datetime import datetime
import logging
from CDocs import db
# Assuming logger and get_document_history are available
logger = logging.getLogger(__name__)
# Generate audit report for a specific document
document_uid = "DOC-12345-ABCD"
report = generate_audit_report(document_uid)
if "error" in report:
print(f"Error generating report: {report['error']}")
else:
print(f"Document: {report['document']['title']}")
print(f"Total versions: {report['versionCount']}")
print(f"Total events: {report['eventCount']}")
print(f"Reviews: {len(report['reviews'])}")
print(f"Approvals: {len(report['approvals'])}")
# Access events by category
for category, events in report['eventsByCategory'].items():
print(f"{category}: {len(events)} events")
# Report generation timestamp
print(f"Report generated at: {report['reportGeneratedAt']}")
Best Practices
- Always check for 'error' key in returned dictionary before accessing report data
- Ensure the document_uid exists in the database before calling this function to avoid unnecessary database queries
- The function depends on get_document_history() being available in the same module - ensure this dependency is satisfied
- Consider caching report results for frequently accessed documents to reduce database load
- The function uses multiple database queries which may be slow for documents with extensive history - consider pagination for large datasets
- Ensure proper error logging is configured as the function logs errors using module-level logger
- The reportGeneratedAt timestamp is in server local time - consider timezone handling for distributed systems
- Review cycles and approvals are ordered by startDate DESC, with most recent first
- Events are categorized using 'eventCategory' field - ensure audit events have this field populated for proper categorization
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function get_document_audit_trail 79.4% similar
-
function get_document_history 77.9% similar
-
function get_document 67.2% similar
-
function get_document_with_relationships 66.1% similar
-
function get_document_training_info 65.7% similar