# Patrol Setup Wizard - Implementation Validation & Testing Guide

## Implementation Status Checklist

### ✅ Service Layer Implementation
- [x] PatrolWizardService created (`app/Services/PatrolWizardService.php`)
- [x] `getEmployeesFromDotNet()` - Fetch from .NET API
- [x] `getClientsFromDotNet($branchCode)` - Fetch clients by branch
- [x] `syncClientsFromDotNet($clients)` - Sync to Laravel database
- [x] `getAvailableServices()` - Get all active services
- [x] `getCheckpointsForService($serviceId)` - Get checkpoints
- [x] `getSchedulesForService($serviceId)` - Get schedules
- [x] `getGeofencesForService($serviceId)` - Get geofences
- [x] `validatePatrolAssignment()` - Validation logic

### ✅ API Controller Implementation
- [x] PatrolWizardApiController created (`app/Http/Controllers/Api/PatrolWizardApiController.php`)
- [x] Employee endpoints (GET, POST)
- [x] Client endpoints (GET with sync)
- [x] Service endpoints (GET)
- [x] Assignment endpoint (POST)
- [x] Checkpoint endpoints (GET)
- [x] Schedule endpoints (GET, POST)
- [x] Geofence endpoints (GET, POST)
- [x] Complete endpoint (POST)
- [x] Error handling with try-catch
- [x] Transaction management

### ✅ Web Controller Implementation
- [x] WizardController rewritten (`app/Http/Controllers/WizardController.php`)
- [x] patrolSetup() method
- [x] storePatrolSetup() method
- [x] handleEmployee() with 3 modes
- [x] handleSiteAssignment() method
- [x] handlePatrolSchedule() method
- [x] handleGeofencing() method
- [x] Helper methods (generateEmployeeCode, buildLocationString)

### ✅ Routing Configuration
- [x] routes/api.php updated
- [x] PatrolWizardApiController imported
- [x] Wizard route group configured
- [x] 11 endpoints registered
- [x] Sanctum middleware applied

### ✅ Database Models
- [x] User model exists
- [x] Profile model exists
- [x] Client model exists
- [x] ClientService model exists
- [x] EmployeeAssignment model exists
- [x] PatrolSchedule model exists
- [x] PatrolCheckpoint model exists
- [x] PatrolTimeSlot model exists
- [x] CheckpointQRCode model exists
- [x] Geofence model exists

### ✅ Documentation
- [x] Patrol_Setup_Wizard_Implementation.md
- [x] Patrol_Wizard_Quick_Start.md
- [x] Patrol_Setup_Wizard_README.md (this document)
- [x] Code comments in all files

## Unit Testing Scenarios

### Scenario 1: Fetch Employees from .NET
```php
// Test: app/Tests/Feature/PatrolWizardTest.php
public function test_fetch_employees_from_dotnet()
{
    $response = $this->actingAs($user, 'sanctum')
        ->getJson('/api/v1/admin/wizard/employees');
    
    $response->assertStatus(200)
        ->assertJson([
            'success' => true,
            'message' => 'Employees retrieved successfully'
        ])
        ->assertJsonStructure([
            'data' => [
                '*' => [
                    'id', 'code', 'name', 'phone', 'branch', 'client'
                ]
            ]
        ]);
}
```

### Scenario 2: Create New Employee
```php
public function test_create_new_employee()
{
    $response = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/employees', [
            'name' => 'New Employee',
            'email' => 'new@example.com',
            'phone' => '9123456789',
            'password' => 'password123'
        ]);
    
    $response->assertStatus(201)
        ->assertJson(['success' => true]);
    
    $this->assertDatabaseHas('users', [
        'name' => 'New Employee',
        'email' => 'new@example.com'
    ]);
}
```

### Scenario 3: Get and Sync Clients
```php
public function test_get_clients_from_dotnet()
{
    $response = $this->actingAs($user, 'sanctum')
        ->getJson('/api/v1/admin/wizard/clients?branch_code=FWG0001-HYD');
    
    $response->assertStatus(200)
        ->assertJson([
            'success' => true,
            'message' => 'Clients retrieved and synced successfully'
        ]);
    
    // Verify clients were synced to database
    $this->assertDatabaseHas('clients', [
        'branch_code' => 'FWG0001-HYD'
    ]);
}
```

### Scenario 4: Assign Employee to Service
```php
public function test_assign_employee_to_service()
{
    $employee = User::factory()->create();
    $service = ClientService::factory()->create();
    
    $response = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/assign-site', [
            'employee_id' => $employee->id,
            'service_id' => $service->id,
            'start_date' => now()->toDateString(),
            'end_date' => now()->addYear()->toDateString()
        ]);
    
    $response->assertStatus(200)
        ->assertJson(['success' => true]);
    
    $this->assertDatabaseHas('employee_assignments', [
        'user_id' => $employee->id,
        'service_id' => $service->id
    ]);
}
```

### Scenario 5: Prevent Duplicate Assignment
```php
public function test_prevent_duplicate_assignment()
{
    $employee = User::factory()->create();
    $service = ClientService::factory()->create();
    
    // Create first assignment
    EmployeeAssignment::create([
        'user_id' => $employee->id,
        'service_id' => $service->id
    ]);
    
    // Try to create duplicate
    $response = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/assign-site', [
            'employee_id' => $employee->id,
            'service_id' => $service->id
        ]);
    
    $response->assertStatus(409) // Conflict
        ->assertJson(['success' => false]);
}
```

### Scenario 6: Create Schedule with Checkpoints
```php
public function test_create_schedule_with_checkpoints()
{
    $service = ClientService::factory()->create();
    
    $response = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/create-schedule', [
            'service_id' => $service->id,
            'schedule_name' => 'Morning Patrol',
            'start_time' => '08:00',
            'end_time' => '16:00',
            'interval_hours' => 2,
            'checkpoints' => [
                ['name' => 'Gate', 'lat' => 17.3850, 'lng' => 78.4867],
                ['name' => 'Building', 'lat' => 17.3855, 'lng' => 78.4870]
            ]
        ]);
    
    $response->assertStatus(200)
        ->assertJson(['success' => true]);
    
    $this->assertDatabaseHas('patrol_schedules', [
        'service_id' => $service->id,
        'schedule_name' => 'Morning Patrol'
    ]);
    
    // Verify checkpoints created
    $this->assertCount(2, PatrolCheckpoint::where('service_id', $service->id)->get());
    
    // Verify QR codes generated
    $this->assertCount(2, CheckpointQRCode::whereIn(
        'checkpoint_id',
        PatrolCheckpoint::where('service_id', $service->id)->pluck('id')
    )->get());
}
```

### Scenario 7: Create Geofence
```php
public function test_create_geofence()
{
    $service = ClientService::factory()->create();
    
    $response = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/create-geofence', [
            'service_id' => $service->id,
            'name' => 'Perimeter',
            'type' => 'radius',
            'latitude' => 17.3850,
            'longitude' => 78.4867,
            'radius' => 500
        ]);
    
    $response->assertStatus(200)
        ->assertJson(['success' => true]);
    
    $this->assertDatabaseHas('geofences', [
        'service_id' => $service->id,
        'name' => 'Perimeter',
        'geofence_type' => 'radius'
    ]);
}
```

## Integration Testing

### Complete Flow Test
```php
public function test_complete_patrol_setup_flow()
{
    $user = User::factory()->create();
    $service = ClientService::factory()->create();
    
    // Step 1: Get employees
    $employeesResponse = $this->actingAs($user, 'sanctum')
        ->getJson('/api/v1/admin/wizard/employees');
    $this->assertTrue($employeesResponse->json('success'));
    
    // Step 2: Get clients
    $clientsResponse = $this->actingAs($user, 'sanctum')
        ->getJson('/api/v1/admin/wizard/clients?branch_code=FWG0001-HYD');
    $this->assertTrue($clientsResponse->json('success'));
    
    // Step 3: Assign employee
    $assignResponse = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/assign-site', [
            'employee_id' => $user->id,
            'service_id' => $service->id
        ]);
    $this->assertTrue($assignResponse->json('success'));
    
    // Step 4: Create schedule
    $scheduleResponse = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/create-schedule', [
            'service_id' => $service->id,
            'schedule_name' => 'Test Schedule',
            'start_time' => '08:00',
            'end_time' => '16:00',
            'interval_hours' => 2,
            'checkpoints' => [
                ['name' => 'CP1', 'lat' => 17.3850, 'lng' => 78.4867]
            ]
        ]);
    $this->assertTrue($scheduleResponse->json('success'));
    
    // Step 5: Create geofence
    $geofenceResponse = $this->actingAs($user, 'sanctum')
        ->postJson('/api/v1/admin/wizard/create-geofence', [
            'service_id' => $service->id,
            'name' => 'Geofence',
            'type' => 'radius',
            'latitude' => 17.3850,
            'longitude' => 78.4867,
            'radius' => 500
        ]);
    $this->assertTrue($geofenceResponse->json('success'));
    
    // Verify all data in database
    $this->assertDatabaseHas('employee_assignments', [
        'user_id' => $user->id,
        'service_id' => $service->id
    ]);
    $this->assertDatabaseHas('patrol_schedules', [
        'service_id' => $service->id
    ]);
    $this->assertDatabaseHas('geofences', [
        'service_id' => $service->id
    ]);
}
```

## Database Validation Queries

### Verify Employee Assignment
```sql
SELECT 
    ea.id,
    u.name as employee_name,
    cs.service_name,
    c.name as client_name,
    ea.created_at
FROM employee_assignments ea
JOIN users u ON ea.user_id = u.id
JOIN client_services cs ON ea.service_id = cs.id
JOIN clients c ON cs.client_id = c.id
ORDER BY ea.created_at DESC;
```

### Verify Patrol Schedule with Checkpoints
```sql
SELECT 
    ps.id,
    ps.schedule_name,
    ps.start_time,
    ps.end_time,
    COUNT(pc.id) as checkpoint_count,
    COUNT(cqc.id) as qr_code_count
FROM patrol_schedules ps
LEFT JOIN patrol_checkpoints pc ON ps.id = pc.schedule_id
LEFT JOIN checkpoint_qr_codes cqc ON pc.id = cqc.checkpoint_id
GROUP BY ps.id, ps.schedule_name, ps.start_time, ps.end_time
ORDER BY ps.created_at DESC;
```

### Verify Geofence Setup
```sql
SELECT 
    g.id,
    g.name,
    g.geofence_type,
    ST_AsText(g.coordinates) as location,
    g.radius,
    g.is_active,
    COUNT(gl.id) as log_count
FROM geofences g
LEFT JOIN geofence_logs gl ON g.id = gl.geofence_id
GROUP BY g.id
ORDER BY g.created_at DESC;
```

### Verify Clients Synced from .NET
```sql
SELECT 
    id,
    dotnet_code,
    name,
    branch_code,
    synced_from_dotnet,
    created_at,
    updated_at
FROM clients
WHERE synced_from_dotnet = 1
ORDER BY created_at DESC;
```

### Complete Setup Summary
```sql
SELECT 
    ea.id as assignment_id,
    u.name as employee,
    cs.service_name as service,
    c.name as client,
    ps.schedule_name,
    g.name as geofence,
    ea.created_at
FROM employee_assignments ea
JOIN users u ON ea.user_id = u.id
JOIN client_services cs ON ea.service_id = cs.id
JOIN clients c ON cs.client_id = c.id
LEFT JOIN patrol_schedules ps ON cs.id = ps.service_id
LEFT JOIN geofences g ON cs.id = g.service_id
ORDER BY ea.created_at DESC
LIMIT 10;
```

## Performance Testing

### Load Test: Create 100 Assignments
```bash
#!/bin/bash
TOKEN="your_token"
SERVICE_ID=1

for i in {1..100}; do
    curl -X POST "http://localhost:8000/api/v1/admin/wizard/assign-site" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d "{
        \"employee_id\": $i,
        \"service_id\": $SERVICE_ID
      }"
    echo "Created assignment $i"
done
```

### Response Time Check
```bash
# Time the API response
time curl -X GET "http://localhost:8000/api/v1/admin/wizard/employees" \
  -H "Authorization: Bearer {token}"
```

## Error Scenarios to Test

### Test 1: Invalid Employee ID
```bash
curl -X POST "http://localhost:8000/api/v1/admin/wizard/assign-site" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "employee_id": 99999,
    "service_id": 1
  }'
```

**Expected**: 404 with "Employee not found"

### Test 2: Invalid Coordinates
```bash
curl -X POST "http://localhost:8000/api/v1/admin/wizard/create-geofence" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "service_id": 1,
    "type": "radius",
    "latitude": 200,
    "longitude": 400,
    "radius": 500
  }'
```

**Expected**: 422 with validation errors

### Test 3: Missing Required Fields
```bash
curl -X POST "http://localhost:8000/api/v1/admin/wizard/create-schedule" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "service_id": 1
  }'
```

**Expected**: 422 with required field errors

### Test 4: Invalid Time Range
```bash
curl -X POST "http://localhost:8000/api/v1/admin/wizard/create-schedule" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "service_id": 1,
    "start_time": "16:00",
    "end_time": "08:00",
    "checkpoints": []
  }'
```

**Expected**: 400 with "End time must be after start time"

### Test 5: Duplicate Assignment
```bash
# First assignment
curl -X POST "http://localhost:8000/api/v1/admin/wizard/assign-site" \
  -H "Authorization: Bearer {token}" \
  -d '{"employee_id": 1, "service_id": 1}'

# Second assignment (should fail)
curl -X POST "http://localhost:8000/api/v1/admin/wizard/assign-site" \
  -H "Authorization: Bearer {token}" \
  -d '{"employee_id": 1, "service_id": 1}'
```

**Expected**: 409 (Conflict) - "Employee is already assigned to this service"

## Monitoring & Debugging

### Enable API Logging
```php
// In patrolSetup() or createSchedule() methods
Log::info('Patrol setup initiated', [
    'employee_id' => $employeeId,
    'service_id' => $serviceId,
    'timestamp' => now()
]);
```

### Check Dotnet API Connectivity
```bash
curl -X GET "http://localhost:5000/api/employee/Employees" -v
```

### Verify Database Connections
```php
// In service method
try {
    DB::connection()->getPdo();
    Log::info('Database connected');
} catch (\Exception $e) {
    Log::error('Database connection failed', ['error' => $e->getMessage()]);
}
```

## Success Criteria

✅ All 11 API endpoints respond correctly
✅ Employees fetch from .NET system
✅ Clients sync to Laravel database
✅ Duplicate assignments prevented
✅ Schedules created with checkpoints
✅ QR codes generated for all checkpoints
✅ Geofences created with validation
✅ Complete flow works end-to-end
✅ Error handling returns proper HTTP status codes
✅ Transaction rollback works on failures
✅ Logging captures all operations

---

**Status**: ✅ Implementation Complete - Ready for Testing
