# Provider Contract Notification System

## Overview

This document describes the complete notification system for the provider contract lifecycle. The system ensures that providers and admins are informed at every critical stage of the contract process.

---

## Architecture

### Event-Driven Design

The system uses Laravel's event/listener architecture:

```
Service Method → Dispatch Event → Listener Handles Event → Send Notification → User Receives Alert
```

All listeners implement `ShouldQueue` for asynchronous processing, ensuring API responses remain fast.

---

## Notification Flow

### 1. Contract Created/Sent

**Trigger:** Admin creates or resends a contract

**Event:** `App\Events\ProviderContracts\ContractSent`

**Dispatched From:**
- `Dashboard\ProviderContractService::store()` - when new contract is created
- `Dashboard\ProviderContractService::resend()` - when contract is resent
- `Dashboard\ProviderContractService::update()` - when rejected contract status changes to SENT

**Listener:** `App\Listeners\ProviderContracts\NotifyProviderContractSent`

**Notification:** `App\Notifications\Provider\ContractSentNotification`

**Recipients:**
- Provider (the contract's target provider)

**Notification Content:**
- Contract number
- Contract title
- Duration and unit
- Number of clauses
- Action link to view contract

**Channels:**
- Database (in-app notification)
- FCM (push notification to mobile)

---

### 2. Contract Accepted

**Trigger:** Provider accepts a contract

**Event:** `App\Events\ProviderContracts\ContractAccepted`

**Dispatched From:**
- `Provider\Contract\ProviderContractService::accept()` - when provider accepts contract

**Listener:** `App\Listeners\ProviderContracts\NotifyAdminsContractAccepted`

**Notification:** `App\Notifications\Admin\ContractAcceptedNotification`

**Recipients:**
- Super admin (role_id = 1)
- All admins with `provider-contracts` permission

**Notification Content:**
- Provider name
- Contract number
- Contract title
- Start date
- End date
- Action link to view contract details

**Channels:**
- Database (in-app notification)
- FCM (push notification to mobile)

---

### 3. Contract Rejected

**Trigger:** Provider rejects a contract

**Event:** `App\Events\ProviderContracts\ContractRejected`

**Dispatched From:**
- `Provider\Contract\ProviderContractService::reject()` - when provider rejects contract

**Listener:** `App\Listeners\ProviderContracts\NotifyAdminsContractRejected`

**Notification:** `App\Notifications\Admin\ContractRejectedNotification`

**Recipients:**
- Super admin (role_id = 1)
- All admins with `provider-contracts` permission

**Notification Content:**
- Provider name
- Contract number
- Contract title
- Rejection reason (provided by provider)
- Action link to view contract and possibly renegotiate

**Channels:**
- Database (in-app notification)
- FCM (push notification to mobile)

---

## Technical Details

### Event Classes

All events are located in `app/Events/ProviderContracts/`:

```php
class ContractSent implements ShouldBroadcast
{
    public function __construct(
        public ProviderContract $contract
    ) {}
}

class ContractAccepted implements ShouldBroadcast
{
    public function __construct(
        public ProviderContract $contract
    ) {}
}

class ContractRejected implements ShouldBroadcast
{
    public function __construct(
        public ProviderContract $contract
    ) {}
}
```

### Listener Classes

All listeners are located in `app/Listeners/ProviderContracts/`:

- `NotifyProviderContractSent` - Handles `ContractSent` event
- `NotifyAdminsContractAccepted` - Handles `ContractAccepted` event
- `NotifyAdminsContractRejected` - Handles `ContractRejected` event

All listeners implement `ShouldQueue` for background processing.

### Notification Classes

**Provider Notifications:**
- `app/Notifications/Provider/ContractSentNotification.php`

**Admin Notifications:**
- `app/Notifications/Admin/ContractAcceptedNotification.php`
- `app/Notifications/Admin/ContractRejectedNotification.php`

### Auto-Discovery

Laravel's event discovery automatically registers listeners based on type-hinted `handle()` methods. No manual registration in `EventServiceProvider` is required.

---

## Admin Recipient Logic

Admin notifications target two groups:

### 1. Super Admin
```php
User::where('role_id', 1)->get()
```

The super admin (role_id = 1) always receives contract notifications.

### 2. Admins with Contract Permissions
```php
User::whereHas('role.permissions', function ($query) {
    $query->where('name', 'provider-contracts');
})->get()
```

Any admin whose role has the `provider-contracts` permission receives notifications.

This ensures only relevant admins are notified, reducing noise.

---

## Notification Data Structure

### Provider Notification (ContractSent)

```json
{
    "title": "عقد جديد",
    "body": "تم إرسال عقد جديد لك: عقد مقدم خدمة مدته سنة واحدة",
    "data": {
        "type": "contract_sent",
        "contract_id": 123,
        "contract_number": "CONT-2024-00123",
        "provider_id": 456,
        "title": "عقد مقدم خدمة",
        "duration": 1,
        "duration_unit": "year",
        "clauses_count": 8,
        "action": "view_contract"
    }
}
```

### Admin Notification (ContractAccepted)

```json
{
    "title": "قبول عقد",
    "body": "قام أحمد محمد بقبول العقد: CONT-2024-00123",
    "data": {
        "type": "contract_accepted",
        "contract_id": 123,
        "contract_number": "CONT-2024-00123",
        "provider_id": 456,
        "provider_name": "أحمد محمد",
        "title": "عقد مقدم خدمة",
        "start_date": "2024-01-15",
        "end_date": "2025-01-15",
        "action": "view_contract_details"
    }
}
```

### Admin Notification (ContractRejected)

```json
{
    "title": "رفض عقد",
    "body": "قام أحمد محمد برفض العقد: CONT-2024-00123",
    "data": {
        "type": "contract_rejected",
        "contract_id": 123,
        "contract_number": "CONT-2024-00123",
        "provider_id": 456,
        "provider_name": "أحمد محمد",
        "title": "عقد مقدم خدمة",
        "rejection_reason": "الشروط غير مناسبة لعملي",
        "action": "view_contract_and_renegotiate"
    }
}
```

---

## Frontend Integration

### Mobile App (FCM)

The mobile app receives FCM push notifications through the `FcmChannel`.

**Handling Contract Notifications:**

```dart
// Example Flutter code
void handleNotification(Map<String, dynamic> data) {
  final type = data['type'];
  
  switch (type) {
    case 'contract_sent':
      // Navigate to contract details screen
      Navigator.pushNamed(
        context, 
        '/provider/contracts/${data['contract_id']}'
      );
      break;
      
    case 'contract_accepted':
    case 'contract_rejected':
      // Navigate to admin contract management
      Navigator.pushNamed(
        context,
        '/admin/provider-contracts/${data['contract_id']}'
      );
      break;
  }
}
```

### Admin Dashboard

**In-App Notifications:**

```javascript
// Example API call to fetch notifications
GET /api/admin/notifications

// Response includes contract notifications
{
  "data": [
    {
      "id": "uuid",
      "type": "App\\Notifications\\Admin\\ContractAcceptedNotification",
      "data": {
        "type": "contract_accepted",
        "contract_id": 123,
        "provider_name": "أحمد محمد",
        // ... rest of notification data
      },
      "read_at": null,
      "created_at": "2024-01-15T10:30:00Z"
    }
  ]
}
```

**Mark as Read:**
```javascript
POST /api/admin/notifications/{id}/read
```

---

## Queue Configuration

All listeners implement `ShouldQueue`, meaning:

1. Events are dispatched synchronously
2. Listeners execute asynchronously via queue
3. Notifications are sent in the background

### Queue Setup

Ensure your queue worker is running:

```bash
php artisan queue:work
```

For production, use Supervisor or similar process manager.

### Testing Queues Locally

```bash
# Run queue worker in verbose mode
php artisan queue:work --verbose

# Or use sync queue driver for testing
# In .env:
QUEUE_CONNECTION=sync
```

---

## Testing

### Manual Testing

**1. Test Contract Creation Notification:**

```bash
# Create a contract via admin panel or API
POST /api/admin/provider-contracts
{
  "provider_id": 1,
  "title": "Test Contract",
  "duration": 1,
  "duration_unit": "year"
}

# Check provider receives notification
GET /api/provider/notifications
```

**2. Test Contract Acceptance Notification:**

```bash
# Accept contract as provider
POST /api/provider/contracts/{id}/accept

# Check admins receive notification
GET /api/admin/notifications
```

**3. Test Contract Rejection Notification:**

```bash
# Reject contract as provider
POST /api/provider/contracts/{id}/reject
{
  "reason": "Terms not suitable"
}

# Check admins receive notification
GET /api/admin/notifications
```

### Automated Testing

Example PHPUnit test:

```php
public function test_contract_sent_notification_dispatched()
{
    Event::fake([ContractSent::class]);
    
    $provider = User::factory()->provider()->create();
    $admin = User::factory()->admin()->create();
    
    $this->actingAs($admin, 'admin')
        ->postJson('/api/admin/provider-contracts', [
            'provider_id' => $provider->id,
            'title' => 'Test Contract',
            'duration' => 1,
            'duration_unit' => 'year',
        ]);
    
    Event::assertDispatched(ContractSent::class);
}
```

---

## Troubleshooting

### Notifications Not Received

**Check Queue:**
```bash
# Ensure queue worker is running
ps aux | grep queue:work

# Check failed jobs
php artisan queue:failed
```

**Check Notification Settings:**
```sql
-- Verify FCM tokens exist
SELECT id, full_name, fcm_token FROM users WHERE id = ?;

-- Check notification records
SELECT * FROM notifications WHERE notifiable_id = ? ORDER BY created_at DESC;
```

**Check Listener Registration:**
```bash
# List registered events
php artisan event:list | grep Contract
```

### Event Not Dispatching

Verify the event is dispatched in service methods:

```php
// Should be present in service methods
event(new ContractSent($contract));
event(new ContractAccepted($contract));
event(new ContractRejected($contract));
```

### Permission Issues

Verify admin permissions are set up correctly:

```sql
-- Check if provider-contracts permission exists
SELECT * FROM permissions WHERE name = 'provider-contracts';

-- Check role permissions
SELECT r.name, p.name 
FROM roles r
JOIN role_permission rp ON r.id = rp.role_id
JOIN permissions p ON rp.permission_id = p.id
WHERE p.name = 'provider-contracts';
```

---

## Summary

The contract notification system provides comprehensive coverage of the contract lifecycle:

✅ **Contract Sent** - Provider is notified when contract is created or resent  
✅ **Contract Accepted** - Admins are notified when provider accepts  
✅ **Contract Rejected** - Admins are notified with rejection reason  

All notifications are:
- Queued for performance
- Sent via multiple channels (database + FCM)
- Properly scoped to relevant recipients
- Rich with actionable data

The system ensures no contract action goes unnoticed, enabling smooth contract negotiation and management.
