242 lines
8.5 KiB
Markdown
242 lines
8.5 KiB
Markdown
# 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**:
|
|
|
|
```typescript
|
|
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:**
|
|
|
|
```typescript
|
|
// 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`:
|
|
|
|
```typescript
|
|
/**
|
|
* 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**
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
---
|
|
|
|
## 📚 **Related Files**
|
|
|
|
- `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
|
|
|