# PKWT Notification System

Sistem notifikasi otomatis untuk mengingatkan tentang kontrak PKWT yang akan berakhir, dilengkapi dengan sistem email notification yang robust dan reusable untuk berbagai modul.

## Fitur

1. **Automatic Notification Generation**: Sistem secara otomatis membuat notifikasi untuk karyawan dengan kontrak PKWT yang akan berakhir dalam periode tertentu (default: 30 hari)
2. **Email Notification System**: Sistem email otomatis dengan retry mechanism, history tracking, dan template email yang professional
3. **Additional Recipients**: Konfigurasi email recipients tambahan selain email employee
4. **Scheduled Checks**: Scheduler berjalan secara otomatis setiap hari untuk mengecek kontrak yang akan berakhir
5. **Manual Trigger**: Dapat dijalankan secara manual melalui API endpoint
6. **Robust Error Handling**: Sistem memiliki error handling yang baik dan tidak akan merusak data yang sudah ada
7. **Reusable Email Service**: Email service dapat digunakan untuk berbagai modul lain di masa depan

## Struktur File

- `notification.model.js` - Model Sequelize untuk Notification
- `notification.service.js` - Business logic untuk Notification (CRUD + PKWT generation + Email sending)
- `notifications.controller.js` - Express router untuk API endpoints
- `pkwtNotificationScheduler.js` - Scheduler untuk automated checks
- `emailNotification.service.js` - Reusable email service untuk berbagai modul
- `emailTemplates/email.pkwtExpiration.js` - Template email untuk PKWT expiration notification

## API Endpoints

### 1. Get All Notifications
```
GET /sapps/notifications
Query Parameters:
- employee_id (optional): Filter by employee ID
- notification_type (optional): Filter by notification type
- is_read (optional): Filter by read status (true/false)
- is_sent (optional): Filter by sent status (true/false)
```

### 2. Get Notifications by Employee
```
GET /sapps/notifications/employee/:employee_id
Query Parameters:
- is_read (optional): Filter by read status
```

### 3. Create Notification
```
POST /sapps/notifications
Body:
{
  "workflow_id": 1,
  "employee_id": 1,
  "notification_type": "PKWT_EXPIRATION",
  "recipient_emails": ["email@example.com"],
  "additional_recipients": ["hr@company.com", "admin@company.com"], // optional: additional email recipients
  "is_sent": false,
  "is_read": false
}
```

### 4. Mark Notification as Read
```
PATCH /sapps/notifications/:id/read
```

### 5. Mark Notification as Sent
```
PATCH /sapps/notifications/:id/sent
```

### 6. Delete Notification
```
DELETE /sapps/notifications/:id
```

### 7. Generate PKWT Notifications (Manual)
```
POST /sapps/notifications/generate-pkwt
Body:
{
  "daysBeforeExpiration": 30,
  "companiesId": [1, 2], // optional
  "doctype_id": 123, // Required: DocType ID for PKWT notifications
  "additional_recipients": ["hr@company.com", "admin@company.com"], // optional: additional email recipients
  "sendEmail": true // optional: send email automatically after creating notifications (default: true)
}
```

### 8. Send Email for Notification
```
POST /sapps/notifications/:id/send-email
```
Mengirim email untuk notifikasi tertentu. Email akan dikirim ke:
- Email employee yang terkait
- Additional recipients yang dikonfigurasi di notification

## Konfigurasi

### 1. Setup DocType untuk PKWT Notifications

Sebelum menggunakan fitur ini, Anda perlu membuat DocType untuk PKWT Notifications di database:

```sql
INSERT INTO doctypes (name, display_name, creation, modified, modified_by, owner, enabled)
VALUES ('PKWT Notification', 'PKWT Notification', NOW(), NOW(), 1, 1, 1);
```

Catat `id` dari DocType yang baru dibuat dan gunakan sebagai `doctype_id` saat memanggil API atau mengkonfigurasi scheduler.

### 2. Konfigurasi Scheduler

Scheduler diinisialisasi secara otomatis saat server startup di `app.js`. Konfigurasi default:

- **Interval**: 24 jam (daily check)
- **Days Before Expiration**: 30 hari
- **Run Immediately**: false (menunggu scheduled run pertama)

Untuk mengubah konfigurasi, edit bagian initialization di `app.js`:

```javascript
const schedulerConfig = {
  intervalHours: 24, // Ubah interval (dalam jam)
  daysBeforeExpiration: 30, // Ubah hari sebelum expiration
  doctype_id: YOUR_DOCTYPE_ID, // Set DocType ID untuk PKWT notifications
  modified_by: 1,
  owner: 1,
  runImmediately: false, // Set true untuk run immediately
};
```

### 3. Manual Scheduler Control

Anda juga dapat mengontrol scheduler secara manual:

```javascript
const pkwtScheduler = require("./apps/sapps/masters/notifications/pkwtNotificationScheduler");

// Start scheduler
pkwtScheduler.startScheduler({
  intervalHours: 24,
  daysBeforeExpiration: 30,
  doctype_id: YOUR_DOCTYPE_ID,
});

// Stop scheduler
pkwtScheduler.stopScheduler();

// Get status
const status = pkwtScheduler.getSchedulerStatus();

// Run check manually
await pkwtScheduler.runPKWTNotificationCheck({
  daysBeforeExpiration: 30,
  doctype_id: YOUR_DOCTYPE_ID,
});
```

## Cara Kerja

1. **Scheduler** berjalan setiap hari (atau sesuai interval yang dikonfigurasi)
2. **Service** mencari semua karyawan dengan:
   - `contract_status = 'PKWT'` atau `employeestatus_id` yang mengandung "PKWT"
   - `contract_end_date` tidak null
   - `contract_end_date` berada dalam range (hari ini sampai hari ini + daysBeforeExpiration)
3. Untuk setiap karyawan yang ditemukan:
   - Membuat Workflow baru (jika belum ada)
   - Membuat Notification dengan `notification_type = 'PKWT_EXPIRATION'`
   - Menghindari duplikasi (tidak membuat notifikasi jika sudah ada untuk karyawan yang sama)
4. **Error Handling**: Jika terjadi error pada satu karyawan, proses tetap lanjut untuk karyawan lainnya

## Filter Karyawan PKWT

Sistem menggunakan filter yang sama dengan `employee.service.js` untuk mencari karyawan PKWT:

1. Prioritas: `contract_status = 'PKWT'` (field baru)
2. Fallback: `employeestatus_id` yang memiliki display_name atau name mengandung "PKWT"

## Notifikasi Type

- `PKWT_EXPIRATION`: Notifikasi untuk kontrak PKWT yang akan berakhir

## Email Notification System

### Fitur Email Service

1. **Reusable Service**: `emailNotification.service.js` dapat digunakan untuk berbagai modul
2. **Retry Mechanism**: Otomatis retry hingga 3 kali jika email gagal dikirim
3. **History Tracking**: Semua email yang dikirim dicatat di `HistoryEmail` table
4. **Multiple Recipients**: Support untuk to, cc, bcc recipients
5. **Additional Recipients**: Konfigurasi email tambahan selain email employee
6. **Professional Template**: Template email mengikuti best practices untuk HTML email

### Email Template PKWT

Template email untuk PKWT expiration notification memiliki:
- **Responsive Design**: Compatible dengan berbagai email client
- **Urgency Indicators**: Warna berbeda berdasarkan hari tersisa (critical, high, medium, normal)
- **Professional Layout**: Mengikuti best practices untuk email HTML
- **Clear Call to Action**: Menjelaskan tindakan yang diperlukan

### Konfigurasi Email Account

Email account dikonfigurasi per company melalui `EmailAccount` dan `Email` tables. Pastikan:
1. Email account sudah dikonfigurasi untuk company yang bersangkutan
2. SMTP settings sudah benar (smtp_server, smtp_port, use_ssl_for_outgoing, use_tls)
3. Email account dan password sudah valid

### Additional Recipients

Additional recipients dapat dikonfigurasi di **2 cara**:

#### 1. Per Company (Recommended - Persistent Configuration)

Konfigurasi di `CompanySetting` table dengan key `pkwt_notification_additional_recipients`. 
Ini adalah cara yang **disarankan** karena konfigurasi akan otomatis digunakan untuk semua PKWT notifications di company tersebut.

**Cara Konfigurasi:**

**A. Menggunakan SQL Script (Recommended):**
```sql
-- File: migrations/pkwt_notification_additional_recipients_config.sql
-- Edit COMPANY_ID dan email addresses sesuai kebutuhan, lalu jalankan script
```

**B. Menggunakan SQL Manual:**
```sql
-- Insert atau Update CompanySetting
INSERT INTO companysettings (company_id, `key`, value, creation, modified, modified_by, owner)
VALUES (
    1, -- COMPANY_ID
    'pkwt_notification_additional_recipients',
    '["hr@company.com", "admin@company.com", "manager@company.com"]', -- JSON array email addresses
    NOW(),
    NOW(),
    1, -- modified_by
    1  -- owner
)
ON DUPLICATE KEY UPDATE
    value = '["hr@company.com", "admin@company.com", "manager@company.com"]',
    modified = NOW(),
    modified_by = 1;
```

**C. Menggunakan API Company Setting:**
Jika ada API untuk update company settings, gunakan:
```json
{
  "settings": {
    "pkwt_notification_additional_recipients": "[\"hr@company.com\", \"admin@company.com\"]"
  }
}
```

**Format Value:**
- Harus berupa JSON array yang valid
- Contoh: `["hr@company.com", "admin@company.com", "manager@company.com"]`
- Untuk menghapus additional recipients, set value menjadi `"[]"` (empty array)

**Prioritas:**
1. Jika `additional_recipients` diberikan di params saat generate notification → digunakan
2. Jika tidak ada di params → sistem akan mengambil dari `CompanySetting` dengan key `pkwt_notification_additional_recipients`
3. Jika tidak ada di CompanySetting → hanya email employee yang dikirim

#### 2. Per Notification (Temporary/Override)

Tambahkan `additional_recipients` saat membuat notification melalui API:

```json
{
  "daysBeforeExpiration": 30,
  "doctype_id": 123,
  "additional_recipients": ["hr@company.com", "admin@company.com"], // Override CompanySetting
  "sendEmail": true
}
```

**Catatan:**
- Jika `additional_recipients` diberikan di params, akan override konfigurasi di CompanySetting
- Jika tidak diberikan, sistem akan otomatis menggunakan konfigurasi dari CompanySetting

### SQL Migration

Jalankan migration untuk menambahkan field `additional_recipients`:

```sql
-- File: migrations/notifications_add_additional_recipients_safe.sql
-- Migration ini aman dan tidak akan merusak data existing
```

Atau jalankan secara manual:
```sql
ALTER TABLE notifications 
ADD COLUMN additional_recipients JSON NULL 
COMMENT "Additional email recipients (array of email addresses) for notifications" 
AFTER recipient_emails;
```

## Database Schema

Notification table memiliki struktur:
- `id`: Primary key
- `workflow_id`: Foreign key ke workflows (required)
- `employee_id`: Foreign key ke employees (required, recipient)
- `notification_type`: Tipe notifikasi (required)
- `recipient_emails`: JSON array email penerima (optional)
- `additional_recipients`: JSON array email recipients tambahan (optional, baru)
- `is_sent`: Status pengiriman (boolean)
- `is_read`: Status pembacaan (boolean)
- `sentAt`: Timestamp pengiriman (optional)

## Catatan Penting

1. **DocType ID**: Pastikan untuk mengkonfigurasi `doctype_id` yang benar sebelum menggunakan fitur ini
2. **Workflow**: Setiap notifikasi memerlukan Workflow. Sistem akan membuat Workflow otomatis jika `doctype_id` dikonfigurasi
3. **Duplikasi**: Sistem mencegah duplikasi notifikasi untuk karyawan yang sama
4. **Error Handling**: Error pada satu karyawan tidak akan menghentikan proses untuk karyawan lainnya
5. **Transaction Safety**: Semua operasi database menggunakan transaction untuk memastikan data integrity

## Troubleshooting

### Scheduler tidak berjalan
- Pastikan server sudah restart setelah menambahkan kode scheduler
- Cek console log untuk melihat apakah scheduler berhasil diinisialisasi
- Pastikan tidak ada error saat require scheduler module

### Notifikasi tidak dibuat
- Pastikan `doctype_id` sudah dikonfigurasi dengan benar
- Cek apakah ada karyawan dengan PKWT yang memenuhi kriteria (contract_end_date dalam range)
- Cek console log untuk melihat error messages
- Pastikan database connection berjalan dengan baik

### Duplikasi notifikasi
- Sistem sudah memiliki mekanisme untuk mencegah duplikasi
- Jika masih terjadi duplikasi, cek apakah ada multiple scheduler yang berjalan
- Pastikan tidak ada manual trigger yang berjalan bersamaan dengan scheduler

## Testing

Untuk testing manual:

1. **Test API Endpoint**:
```bash
# Generate notifications manually
curl -X POST http://localhost:3000/sapps/notifications/generate-pkwt \
  -H "Content-Type: application/json" \
  -d '{
    "daysBeforeExpiration": 30,
    "doctype_id": YOUR_DOCTYPE_ID
  }'

# Get all notifications
curl http://localhost:3000/sapps/notifications

# Get notifications by employee
curl http://localhost:3000/sapps/notifications/employee/1
```

2. **Test Scheduler**:
```javascript
const pkwtScheduler = require("./apps/sapps/masters/notifications/pkwtNotificationScheduler");

// Run check immediately
await pkwtScheduler.runPKWTNotificationCheck({
  daysBeforeExpiration: 30,
  doctype_id: YOUR_DOCTYPE_ID,
});
```

## Email Notification Flow

1. **Notification Created**: Saat notification dibuat (via scheduler atau manual)
2. **Email Triggered**: Jika `sendEmail: true`, email otomatis dikirim setelah notification dibuat
3. **Email Service**: `emailNotification.service.js` mengambil email account dari company
4. **Template Rendering**: Template email di-render dengan data employee dan contract info
5. **Email Sending**: Email dikirim ke:
   - Employee email (jika ada)
   - Additional recipients (jika dikonfigurasi)
6. **Retry Mechanism**: Jika gagal, akan retry hingga 3 kali dengan delay 5 detik
7. **History Tracking**: Semua email dicatat di `HistoryEmail` table dengan status (sent/failed)
8. **Notification Update**: Status `is_sent` dan `sentAt` di-update setelah email berhasil dikirim

## Monitoring Email Notifications

Untuk monitoring email notifications:

1. **Check HistoryEmail Table**:
```sql
SELECT * FROM historyemails 
WHERE employee_id = YOUR_EMPLOYEE_ID 
ORDER BY creation DESC;
```

2. **Check Notification Status**:
```sql
SELECT id, notification_type, is_sent, sentAt, additional_recipients 
FROM notifications 
WHERE notification_type = 'PKWT_EXPIRATION' 
ORDER BY creation DESC;
```

3. **Check Failed Emails**:
```sql
SELECT * FROM historyemails 
WHERE status = 'failed' 
ORDER BY creation DESC;
```

## Best Practices

1. **Email Account Configuration**: Pastikan email account sudah dikonfigurasi dengan benar sebelum menggunakan fitur email
2. **Additional Recipients**: Gunakan additional recipients untuk mengirim email ke HR, manager, atau admin yang terkait
3. **Retry Mechanism**: Sistem sudah memiliki retry mechanism, tetapi pastikan email server tidak overload
4. **Template Customization**: Template email dapat dikustomisasi di `emailTemplates/email.pkwtExpiration.js`
5. **Error Handling**: Semua error dicatat di `HistoryEmail.error_message` untuk troubleshooting

## Future Enhancements

1. ✅ Email notification integration (DONE)
2. Multiple notification types (beyond PKWT)
3. Configurable notification templates per company/module
4. Dashboard untuk melihat email statistics
5. Webhook support untuk external integrations
6. Email queue system untuk handling large volume
7. Email template editor di UI
8. Email delivery reports dan analytics
