function get_approval_statistics
Retrieves and calculates approval cycle statistics for a specified date range, including counts by status, average completion time, and overdue approvals.
/tf/active/vicechatdev/CDocs/controllers/approval_controller_bis.py
1403 - 1493
moderate
Purpose
This function provides comprehensive reporting statistics for approval cycles within a document management system. It queries a Neo4j graph database to aggregate approval data, including total approvals, status breakdowns (approved, rejected, in progress, cancelled), average completion time in days, and current overdue approvals. The function enforces permission checks to ensure only authorized users can view reports and provides default date ranges if not specified.
Source Code
def get_approval_statistics(
user: DocUser,
date_from: Optional[datetime] = None,
date_to: Optional[datetime] = None
) -> Dict[str, Any]:
"""
Get approval statistics for reporting.
Args:
user: The requesting user
date_from: Start date for statistics
date_to: End date for statistics
Returns:
Dictionary with approval statistics
"""
try:
# Check permissions
if not permissions.user_has_permission(user, "VIEW_REPORTS"):
raise PermissionError("You do not have permission to view approval statistics")
# Set default date range if not provided
if not date_to:
date_to = datetime.now()
if not date_from:
date_from = date_to - timedelta(days=30) # Last 30 days by default
# Query statistics
result = db.run_query(
"""
MATCH (a:ApprovalCycle)
WHERE a.createdAt >= $date_from AND a.createdAt <= $date_to
RETURN
count(a) as total_approvals,
sum(CASE WHEN a.status = 'APPROVED' THEN 1 ELSE 0 END) as approved_count,
sum(CASE WHEN a.status = 'REJECTED' THEN 1 ELSE 0 END) as rejected_count,
sum(CASE WHEN a.status = 'IN_APPROVAL' THEN 1 ELSE 0 END) as in_progress_count,
sum(CASE WHEN a.status = 'CANCELLED' THEN 1 ELSE 0 END) as cancelled_count,
avg(CASE
WHEN a.completionDate IS NOT NULL
THEN duration.between(a.createdAt, a.completionDate).days
ELSE null
END) as avg_completion_days
""",
{
"date_from": date_from,
"date_to": date_to
}
)
# Process statistics
stats = result[0] if result else {}
# Get overdue approvals
overdue_query = db.run_query(
"""
MATCH (a:ApprovalCycle)
WHERE a.status = 'IN_APPROVAL' AND a.dueDate < datetime()
RETURN count(a) as overdue_count
"""
)
overdue_count = overdue_query[0]['overdue_count'] if overdue_query else 0
return {
"success": True,
"statistics": {
"total_approvals": stats.get('total_approvals', 0),
"approved_count": stats.get('approved_count', 0),
"rejected_count": stats.get('rejected_count', 0),
"in_progress_count": stats.get('in_progress_count', 0),
"cancelled_count": stats.get('cancelled_count', 0),
"overdue_count": overdue_count,
"avg_completion_days": stats.get('avg_completion_days', 0)
},
"period": {
"from": date_from.isoformat(),
"to": date_to.isoformat()
}
}
except PermissionError as e:
logger.warning(f"Permission error getting approval statistics: {e}")
return {"success": False, "message": str(e)}
except Exception as e:
logger.error(f"Unexpected error getting approval statistics: {e}")
import traceback
logger.error(traceback.format_exc())
return {"success": False, "message": "An unexpected error occurred"}
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
user |
DocUser | - | positional_or_keyword |
date_from |
Optional[datetime] | None | positional_or_keyword |
date_to |
Optional[datetime] | None | positional_or_keyword |
Parameter Details
user: A DocUser object representing the requesting user. Must have 'VIEW_REPORTS' permission to access approval statistics. Used for authorization checks.
date_from: Optional datetime object specifying the start date for the statistics query. If not provided, defaults to 30 days before date_to. Filters ApprovalCycle nodes by their createdAt timestamp.
date_to: Optional datetime object specifying the end date for the statistics query. If not provided, defaults to the current datetime. Filters ApprovalCycle nodes by their createdAt timestamp.
Return Value
Type: Dict[str, Any]
Returns a dictionary with structure: {'success': bool, 'statistics': dict, 'period': dict, 'message': str}. On success, 'statistics' contains total_approvals, approved_count, rejected_count, in_progress_count, cancelled_count, overdue_count, and avg_completion_days. The 'period' key contains ISO-formatted 'from' and 'to' dates. On failure, returns {'success': False, 'message': error_description}.
Dependencies
typingdatetimeloggingtracebackCDocs
Required Imports
from typing import Dict, Any, Optional
from datetime import datetime, timedelta
import logging
from CDocs import db
from CDocs.config import permissions
from CDocs.models.user_extensions import DocUser
from CDocs.controllers import log_controller_action, PermissionError
Conditional/Optional Imports
These imports are only needed under specific conditions:
import traceback
Condition: only used in exception handling for detailed error logging
OptionalUsage Example
from datetime import datetime, timedelta
from CDocs.models.user_extensions import DocUser
from CDocs.controllers import get_approval_statistics
# Get statistics for the last 30 days (default)
user = DocUser.get_by_id('user123')
stats = get_approval_statistics(user)
if stats['success']:
print(f"Total approvals: {stats['statistics']['total_approvals']}")
print(f"Approved: {stats['statistics']['approved_count']}")
print(f"Average completion: {stats['statistics']['avg_completion_days']} days")
# Get statistics for a custom date range
date_from = datetime(2024, 1, 1)
date_to = datetime(2024, 1, 31)
stats = get_approval_statistics(user, date_from, date_to)
if not stats['success']:
print(f"Error: {stats['message']}")
Best Practices
- Always check the 'success' field in the returned dictionary before accessing statistics data
- Ensure the user object has the 'VIEW_REPORTS' permission before calling this function to avoid PermissionError
- Use appropriate date ranges to avoid performance issues with large datasets; the default 30-day range is recommended
- The function is decorated with @log_controller_action, so all calls are automatically logged for audit purposes
- Handle both PermissionError and general Exception cases when calling this function
- The avg_completion_days calculation only includes completed approval cycles (those with completionDate set)
- Overdue count is calculated separately and represents current overdue approvals, not historical ones within the date range
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function get_approval_statistics_v1 83.8% similar
-
function get_review_statistics 69.5% similar
-
function get_approval_cycle 68.4% similar
-
function get_user_pending_approvals 66.8% similar
-
function get_user_assigned_approvals 64.5% similar