Re_Backend/Business_Days_Calculation_Recommendations.md

8.5 KiB

Business Days Calculation - Current Issues & Recommendations

🔴 CRITICAL ISSUE: TAT Processor Using Wrong Calculation

Current Problem:

In Re_Backend/src/queues/tatProcessor.ts (lines 64-65), the TAT calculation uses simple calendar hours:

const elapsedMs = now.getTime() - new Date(levelStartTime).getTime();
const elapsedHours = elapsedMs / (1000 * 60 * 60);

This is WRONG because:

  • Counts ALL hours (24/7), including nights, weekends, holidays
  • Doesn't respect working hours (9 AM - 6 PM)
  • Doesn't exclude weekends for STANDARD priority
  • Doesn't exclude holidays
  • Causes incorrect TAT breach alerts

Solution Available:

You already have a proper function calculateElapsedWorkingHours() in tatTimeUtils.ts that:

  • Respects working hours (9 AM - 6 PM)
  • Excludes weekends for STANDARD priority
  • Excludes holidays
  • Handles EXPRESS vs STANDARD differently
  • Uses minute-by-minute precision

🔧 Fix Required:

Update tatProcessor.ts to use proper working hours calculation:

// BEFORE (WRONG):
const elapsedMs = now.getTime() - new Date(levelStartTime).getTime();
const elapsedHours = elapsedMs / (1000 * 60 * 60);

// AFTER (CORRECT):
import { calculateElapsedWorkingHours } from '@utils/tatTimeUtils';
const priority = ((workflow as any).priority || 'STANDARD').toString().toLowerCase();
const elapsedHours = await calculateElapsedWorkingHours(levelStartTime, now, priority);

📊 Business Days Calculation for Workflow Aging Report

Current Situation:

  • You have calculateElapsedWorkingHours() - calculates hours
  • You DON'T have calculateBusinessDays() - calculates days

Need:

For the Workflow Aging Report, you need to show "Days Open" as business days (excluding weekends and holidays), not calendar days.

🔧 Solution: Add Business Days Function

Add this function to Re_Backend/src/utils/tatTimeUtils.ts:

/**
 * Calculate business days between two dates
 * Excludes weekends and holidays
 * @param startDate - Start date
 * @param endDate - End date (defaults to now)
 * @param priority - 'express' or 'standard' (express includes weekends, standard excludes)
 * @returns Number of business days
 */
export async function calculateBusinessDays(
  startDate: Date | string,
  endDate: Date | string | null = null,
  priority: string = 'standard'
): Promise<number> {
  await loadWorkingHoursCache();
  await loadHolidaysCache();
  
  let start = dayjs(startDate).startOf('day');
  const end = dayjs(endDate || new Date()).startOf('day');
  
  // In test mode, use calendar days
  if (isTestMode()) {
    return end.diff(start, 'day') + 1;
  }
  
  const config = workingHoursCache || {
    startHour: TAT_CONFIG.WORK_START_HOUR,
    endHour: TAT_CONFIG.WORK_END_HOUR,
    startDay: TAT_CONFIG.WORK_START_DAY,
    endDay: TAT_CONFIG.WORK_END_DAY
  };
  
  let businessDays = 0;
  let current = start;
  
  // Count each day from start to end (inclusive)
  while (current.isBefore(end) || current.isSame(end, 'day')) {
    const dayOfWeek = current.day(); // 0 = Sunday, 6 = Saturday
    const dateStr = current.format('YYYY-MM-DD');
    
    // For express priority: count all days (including weekends) but exclude holidays
    // For standard priority: count only working days (Mon-Fri) and exclude holidays
    const isWorkingDay = priority === 'express' 
      ? true  // Express includes weekends
      : (dayOfWeek >= config.startDay && dayOfWeek <= config.endDay);
    
    const isNotHoliday = !holidaysCache.has(dateStr);
    
    if (isWorkingDay && isNotHoliday) {
      businessDays++;
    }
    
    current = current.add(1, 'day');
    
    // Safety check to prevent infinite loops
    if (current.diff(start, 'day') > 730) { // 2 years
      console.error('[TAT] Safety break - exceeded 2 years in business days calculation');
      break;
    }
  }
  
  return businessDays;
}

📋 Summary of Issues & Fixes

Issue 1: TAT Processor Using Calendar Hours FIXED

  • File: Re_Backend/src/queues/tatProcessor.ts
  • Line: 64-65 (now 66-77)
  • Problem: Uses simple calendar hours instead of working hours
  • Impact: Incorrect TAT breach calculations
  • Fix: Replaced with calculateElapsedWorkingHours() and addWorkingHours()/addWorkingHoursExpress()
  • Status: COMPLETED - Now uses proper working hours calculation

Issue 2: Missing Business Days Function FIXED

  • File: Re_Backend/src/utils/tatTimeUtils.ts
  • Problem: No function to calculate business days count
  • Impact: Workflow Aging Report shows calendar days instead of business days
  • Fix: Added calculateBusinessDays() function (lines 697-758)
  • Status: COMPLETED - Function implemented and exported

Issue 3: Workflow Aging Report Using Calendar Days FIXED

  • File: Re_Backend/src/services/dashboard.service.ts
  • Problem: Will use calendar days if not fixed
  • Impact: Incorrect "Days Open" calculation
  • Fix: Uses calculateBusinessDays() in report endpoint (getWorkflowAgingReport method)
  • Status: COMPLETED - Report now uses business days calculation

🛠️ Implementation Steps ALL COMPLETED

Step 1: Fix TAT Processor (CRITICAL) DONE

  1. Opened Re_Backend/src/queues/tatProcessor.ts
  2. Imported calculateElapsedWorkingHours, addWorkingHours, addWorkingHoursExpress from @utils/tatTimeUtils
  3. Replaced lines 64-65 with proper working hours calculation (now lines 66-77)
  4. Gets priority from workflow
  5. TODO: Test TAT breach alerts

Step 2: Add Business Days Function DONE

  1. Opened Re_Backend/src/utils/tatTimeUtils.ts
  2. Added calculateBusinessDays() function (lines 697-758)
  3. Exported the function
  4. TODO: Test with various date ranges

Step 3: Update Workflow Aging Report DONE

  1. Built report endpoint using calculateBusinessDays()
  2. Filters requests where businessDays > threshold
  3. Displays business days instead of calendar days

What's Already Working

  • calculateElapsedWorkingHours() - Properly calculates working hours
  • calculateSLAStatus() - Comprehensive SLA calculation
  • Working hours configuration (from admin settings)
  • Holiday support (from database)
  • Priority-based calculation (express vs standard)
  • Used correctly in approval.service.ts and dashboard.service.ts

🎯 Priority Order

  1. 🔴 CRITICAL: Fix TAT Processor (affects all TAT calculations)
  2. 🟡 HIGH: Add Business Days Function (needed for reports)
  3. 🟡 HIGH: Update Workflow Aging Report to use business days

📝 Code Example: Fixed TAT Processor

// In tatProcessor.ts, around line 60-70
import { calculateElapsedWorkingHours } from '@utils/tatTimeUtils';

// ... existing code ...

const tatHours = Number((approvalLevel as any).tatHours || 0);
const levelStartTime = (approvalLevel as any).levelStartTime || (approvalLevel as any).createdAt;
const now = new Date();

// FIXED: Use proper working hours calculation
const priority = ((workflow as any).priority || 'STANDARD').toString().toLowerCase();
const elapsedHours = await calculateElapsedWorkingHours(levelStartTime, now, priority);
const remainingHours = Math.max(0, tatHours - elapsedHours);
const expectedCompletionTime = dayjs(levelStartTime).add(tatHours, 'hour').toDate();

// ... rest of code ...

🧪 Testing Recommendations

  1. Test TAT Breach Calculation:

    • Create a request with 8-hour TAT
    • Submit on Friday 5 PM
    • Should NOT breach until Monday 1 PM (next working hour)
    • Currently will breach on Saturday 1 AM (wrong!)
  2. Test Business Days:

    • Start: Monday, Jan 1
    • End: Friday, Jan 5
    • Should return: 5 business days (not 5 calendar days if there are holidays)
  3. Test Express vs Standard:

    • Express: Should count weekends
    • Standard: Should exclude weekends

  • Re_Backend/src/queues/tatProcessor.ts - FIXED - Now uses calculateElapsedWorkingHours() and proper deadline calculation
  • Re_Backend/src/utils/tatTimeUtils.ts - FIXED - Added calculateBusinessDays() function
  • Re_Backend/src/services/approval.service.ts - Already using correct calculation
  • Re_Backend/src/services/dashboard.service.ts - FIXED - Uses calculateBusinessDays() in Workflow Aging Report
  • Re_Backend/src/services/workflow.service.ts - Already using correct calculation