468 lines
9.9 KiB
Markdown
468 lines
9.9 KiB
Markdown
## 📅 Holiday Calendar System - Complete Guide
|
|
|
|
## Overview
|
|
|
|
The Holiday Calendar System allows administrators to manage organizational holidays that are excluded from TAT (Turnaround Time) calculations for **STANDARD priority** requests.
|
|
|
|
**Key Features:**
|
|
- ✅ Admin can add/edit/delete holidays
|
|
- ✅ Supports different holiday types (National, Regional, Organizational, Optional)
|
|
- ✅ Recurring holidays (e.g., Independence Day every year)
|
|
- ✅ Department/location-specific holidays
|
|
- ✅ Bulk import from CSV/JSON
|
|
- ✅ Automatic integration with TAT calculations
|
|
- ✅ Year-based calendar view
|
|
|
|
---
|
|
|
|
## 🎯 How It Works
|
|
|
|
### **For STANDARD Priority:**
|
|
```
|
|
Working Days = Monday-Friday (excluding weekends AND holidays)
|
|
TAT Calculation = Skips Saturdays, Sundays, AND holidays
|
|
```
|
|
|
|
### **For EXPRESS Priority:**
|
|
```
|
|
Calendar Days = All days (including weekends and holidays)
|
|
TAT Calculation = Continuous (no skipping)
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Database Schema
|
|
|
|
### **Holidays Table:**
|
|
|
|
```sql
|
|
CREATE TABLE holidays (
|
|
holiday_id UUID PRIMARY KEY,
|
|
holiday_date DATE NOT NULL UNIQUE,
|
|
holiday_name VARCHAR(200) NOT NULL,
|
|
description TEXT,
|
|
is_recurring BOOLEAN DEFAULT false,
|
|
recurrence_rule VARCHAR(100), -- For annual recurring
|
|
holiday_type ENUM('NATIONAL', 'REGIONAL', 'ORGANIZATIONAL', 'OPTIONAL'),
|
|
is_active BOOLEAN DEFAULT true,
|
|
applies_to_departments TEXT[], -- NULL = all departments
|
|
applies_to_locations TEXT[], -- NULL = all locations
|
|
created_by UUID REFERENCES users(user_id),
|
|
updated_by UUID REFERENCES users(user_id),
|
|
created_at TIMESTAMP,
|
|
updated_at TIMESTAMP
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## 🔌 API Endpoints
|
|
|
|
### **1. Get All Holidays**
|
|
```
|
|
GET /api/admin/holidays?year=2025
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": [
|
|
{
|
|
"holidayId": "...",
|
|
"holidayDate": "2025-01-26",
|
|
"holidayName": "Republic Day",
|
|
"description": "Indian Republic Day",
|
|
"holidayType": "NATIONAL",
|
|
"isRecurring": true,
|
|
"isActive": true
|
|
}
|
|
],
|
|
"count": 15
|
|
}
|
|
```
|
|
|
|
### **2. Get Holiday Calendar for Year**
|
|
```
|
|
GET /api/admin/holidays/calendar/2025
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"year": 2025,
|
|
"holidays": [
|
|
{
|
|
"date": "2025-01-26",
|
|
"name": "Republic Day",
|
|
"description": "...",
|
|
"type": "NATIONAL",
|
|
"isRecurring": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### **3. Create Holiday**
|
|
```
|
|
POST /api/admin/holidays
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"holidayDate": "2025-10-02",
|
|
"holidayName": "Gandhi Jayanti",
|
|
"description": "Mahatma Gandhi's Birthday",
|
|
"holidayType": "NATIONAL",
|
|
"isRecurring": true,
|
|
"recurrenceRule": "FREQ=YEARLY;BYMONTH=10;BYMONTHDAY=2"
|
|
}
|
|
```
|
|
|
|
### **4. Update Holiday**
|
|
```
|
|
PUT /api/admin/holidays/:holidayId
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"holidayName": "Updated Name",
|
|
"description": "Updated description"
|
|
}
|
|
```
|
|
|
|
### **5. Delete Holiday**
|
|
```
|
|
DELETE /api/admin/holidays/:holidayId
|
|
```
|
|
|
|
### **6. Bulk Import Holidays**
|
|
```
|
|
POST /api/admin/holidays/bulk-import
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"holidays": [
|
|
{
|
|
"holidayDate": "2025-01-26",
|
|
"holidayName": "Republic Day",
|
|
"holidayType": "NATIONAL"
|
|
},
|
|
{
|
|
"holidayDate": "2025-08-15",
|
|
"holidayName": "Independence Day",
|
|
"holidayType": "NATIONAL"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🎨 Frontend Implementation (Future)
|
|
|
|
### **Holiday Management Page:**
|
|
|
|
```tsx
|
|
// Admin Dashboard → Settings → Holiday Calendar
|
|
|
|
<HolidayCalendar>
|
|
<YearSelector currentYear={2025} />
|
|
|
|
<CalendarView>
|
|
{/* Visual calendar showing all holidays */}
|
|
<Day date="2025-01-26" isHoliday>
|
|
Republic Day
|
|
</Day>
|
|
</CalendarView>
|
|
|
|
<HolidayList>
|
|
{/* List view with add/edit/delete */}
|
|
<HolidayCard>
|
|
📅 Jan 26, 2025 - Republic Day
|
|
<Actions>
|
|
<EditButton />
|
|
<DeleteButton />
|
|
</Actions>
|
|
</HolidayCard>
|
|
</HolidayList>
|
|
|
|
<AddHolidayButton onClick={openModal} />
|
|
<BulkImportButton onClick={openImportDialog} />
|
|
</HolidayCalendar>
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 Sample Holidays Data
|
|
|
|
### **Indian National Holidays 2025:**
|
|
|
|
```json
|
|
[
|
|
{ "date": "2025-01-26", "name": "Republic Day", "type": "NATIONAL" },
|
|
{ "date": "2025-03-14", "name": "Holi", "type": "NATIONAL" },
|
|
{ "date": "2025-03-30", "name": "Ram Navami", "type": "NATIONAL" },
|
|
{ "date": "2025-04-10", "name": "Mahavir Jayanti", "type": "NATIONAL" },
|
|
{ "date": "2025-04-14", "name": "Ambedkar Jayanti", "type": "NATIONAL" },
|
|
{ "date": "2025-04-18", "name": "Good Friday", "type": "NATIONAL" },
|
|
{ "date": "2025-05-01", "name": "May Day", "type": "NATIONAL" },
|
|
{ "date": "2025-08-15", "name": "Independence Day", "type": "NATIONAL" },
|
|
{ "date": "2025-08-27", "name": "Janmashtami", "type": "NATIONAL" },
|
|
{ "date": "2025-10-02", "name": "Gandhi Jayanti", "type": "NATIONAL" },
|
|
{ "date": "2025-10-22", "name": "Dussehra", "type": "NATIONAL" },
|
|
{ "date": "2025-11-01", "name": "Diwali", "type": "NATIONAL" },
|
|
{ "date": "2025-11-05", "name": "Guru Nanak Jayanti", "type": "NATIONAL" },
|
|
{ "date": "2025-12-25", "name": "Christmas", "type": "NATIONAL" }
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 TAT Calculation Integration
|
|
|
|
### **How Holidays Affect TAT:**
|
|
|
|
**Example: 48-hour TAT for STANDARD priority**
|
|
|
|
**Without Holidays:**
|
|
```
|
|
Submit: Monday 10:00 AM
|
|
Due: Wednesday 10:00 AM (48 working hours, skipping weekend)
|
|
```
|
|
|
|
**With Holiday (Tuesday is holiday):**
|
|
```
|
|
Submit: Monday 10:00 AM
|
|
Holiday: Tuesday (skipped)
|
|
Due: Thursday 10:00 AM (48 working hours, skipping Tuesday AND weekend)
|
|
```
|
|
|
|
### **TAT Calculation Logic:**
|
|
|
|
```typescript
|
|
// For STANDARD priority:
|
|
1. Start from submission time
|
|
2. Add hours one by one
|
|
3. Skip if:
|
|
- Weekend (Saturday/Sunday)
|
|
- Outside working hours (before 9 AM or after 6 PM)
|
|
- Holiday (from holidays table)
|
|
4. Continue until all hours are added
|
|
```
|
|
|
|
---
|
|
|
|
## 🏗️ Architecture
|
|
|
|
### **Holiday Cache System:**
|
|
|
|
```
|
|
Server Startup
|
|
↓
|
|
Load holidays from database
|
|
↓
|
|
Cache in memory (Set of dates)
|
|
↓
|
|
Cache expires after 6 hours
|
|
↓
|
|
Reload automatically
|
|
```
|
|
|
|
**Benefits:**
|
|
- ✅ Fast lookups (no DB query for each hour)
|
|
- ✅ Automatic refresh
|
|
- ✅ Minimal memory footprint
|
|
|
|
### **TAT Calculation Flow:**
|
|
|
|
```
|
|
calculateTatMilestones()
|
|
↓
|
|
addWorkingHours()
|
|
↓
|
|
loadHolidaysCache() (if expired)
|
|
↓
|
|
For each hour:
|
|
isWorkingTime()
|
|
├─ Check weekend? → Skip
|
|
├─ Check working hours? → Skip if outside
|
|
└─ Check holiday? → Skip if holiday
|
|
↓
|
|
Return calculated date
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 Admin Configuration
|
|
|
|
### **Admin Can Configure:**
|
|
|
|
| Config Area | Options | Default |
|
|
|-------------|---------|---------|
|
|
| **TAT Settings** | Default TAT hours (Express/Standard) | 24h/48h |
|
|
| | Reminder thresholds | 50%, 75% |
|
|
| | Working hours | 9 AM - 6 PM |
|
|
| **Holidays** | Add/edit/delete holidays | None |
|
|
| | Bulk import holidays | - |
|
|
| | Recurring holidays | - |
|
|
| **Document Policy** | Max file size | 10 MB |
|
|
| | Allowed file types | pdf,doc,... |
|
|
| | Retention period | 365 days |
|
|
| **AI Configuration** | Enable/disable AI remarks | Enabled |
|
|
| | Max characters | 500 |
|
|
| **Notifications** | Channels (email/push) | All |
|
|
| | Frequency | Immediate |
|
|
|
|
---
|
|
|
|
## 🧪 Testing Holiday Integration
|
|
|
|
### **Test Scenario 1: Add Holiday**
|
|
|
|
```bash
|
|
# 1. Add a holiday for tomorrow
|
|
POST /api/admin/holidays
|
|
{
|
|
"holidayDate": "2025-11-05",
|
|
"holidayName": "Test Holiday",
|
|
"holidayType": "ORGANIZATIONAL"
|
|
}
|
|
|
|
# 2. Create request with 24-hour STANDARD TAT
|
|
# Expected: Due date should skip the holiday
|
|
|
|
# 3. Verify TAT calculation excludes the holiday
|
|
```
|
|
|
|
### **Test Scenario 2: Recurring Holiday**
|
|
|
|
```bash
|
|
# 1. Add Independence Day (recurring)
|
|
POST /api/admin/holidays
|
|
{
|
|
"holidayDate": "2025-08-15",
|
|
"holidayName": "Independence Day",
|
|
"isRecurring": true,
|
|
"recurrenceRule": "FREQ=YEARLY;BYMONTH=8;BYMONTHDAY=15"
|
|
}
|
|
|
|
# 2. Test requests spanning this date
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Holiday Statistics API
|
|
|
|
### **Get Holiday Count by Type:**
|
|
|
|
```sql
|
|
SELECT
|
|
holiday_type,
|
|
COUNT(*) as count
|
|
FROM holidays
|
|
WHERE is_active = true
|
|
AND EXTRACT(YEAR FROM holiday_date) = 2025
|
|
GROUP BY holiday_type;
|
|
```
|
|
|
|
### **Get Upcoming Holidays:**
|
|
|
|
```sql
|
|
SELECT
|
|
holiday_name,
|
|
holiday_date,
|
|
holiday_type
|
|
FROM holidays
|
|
WHERE holiday_date >= CURRENT_DATE
|
|
AND holiday_date <= CURRENT_DATE + INTERVAL '90 days'
|
|
AND is_active = true
|
|
ORDER BY holiday_date;
|
|
```
|
|
|
|
---
|
|
|
|
## 🔒 Security
|
|
|
|
### **Admin Only Access:**
|
|
|
|
All holiday and configuration management endpoints require:
|
|
1. ✅ Valid JWT token (`authenticateToken`)
|
|
2. ✅ Admin role (`requireAdmin`)
|
|
|
|
**Middleware Chain:**
|
|
```typescript
|
|
router.use(authenticateToken); // Must be logged in
|
|
router.use(requireAdmin); // Must be admin
|
|
```
|
|
|
|
---
|
|
|
|
## 🎓 Best Practices
|
|
|
|
### **1. Holiday Naming:**
|
|
- Use clear, descriptive names
|
|
- Include year if not recurring
|
|
- Example: "Diwali 2025" or "Independence Day" (recurring)
|
|
|
|
### **2. Types:**
|
|
- **NATIONAL**: Applies to entire country
|
|
- **REGIONAL**: Specific to state/region
|
|
- **ORGANIZATIONAL**: Company-specific
|
|
- **OPTIONAL**: Optional holidays (float)
|
|
|
|
### **3. Department/Location Specific:**
|
|
```json
|
|
{
|
|
"holidayName": "Regional Holiday",
|
|
"appliesToDepartments": ["Sales", "Marketing"],
|
|
"appliesToLocations": ["Mumbai", "Delhi"]
|
|
}
|
|
```
|
|
|
|
### **4. Recurring Holidays:**
|
|
```json
|
|
{
|
|
"isRecurring": true,
|
|
"recurrenceRule": "FREQ=YEARLY;BYMONTH=8;BYMONTHDAY=15"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Deployment
|
|
|
|
### **Initial Setup:**
|
|
|
|
1. **Run Migrations:**
|
|
```bash
|
|
npm run migrate
|
|
```
|
|
|
|
2. **Import Indian Holidays:**
|
|
```bash
|
|
curl -X POST http://localhost:5000/api/admin/holidays/bulk-import \
|
|
-H "Content-Type: application/json" \
|
|
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
|
|
-d @sample_holidays_2025.json
|
|
```
|
|
|
|
3. **Verify:**
|
|
```bash
|
|
curl http://localhost:5000/api/admin/holidays?year=2025
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Related Documentation
|
|
|
|
- **Admin Configuration**: See admin configuration tables
|
|
- **TAT Calculation**: See `TAT_NOTIFICATION_SYSTEM.md`
|
|
- **API Reference**: See API documentation
|
|
|
|
---
|
|
|
|
**Last Updated**: November 4, 2025
|
|
**Version**: 1.0.0
|
|
**Team**: Royal Enfield Workflow
|
|
|