155 lines
5.6 KiB
PHP
155 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Api\V1\Trip;
|
|
|
|
use App\Models\CollectionTeam;
|
|
use App\Models\DropOffPoint;
|
|
use App\Models\Dumpsite;
|
|
use App\Models\QrCode;
|
|
use App\Models\Route;
|
|
use App\Models\Trip;
|
|
use App\Models\User;
|
|
use Database\Seeders\RoleSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class E2EWasteCollectionTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_full_waste_collection_lifecycle_end_to_end()
|
|
{
|
|
// 1. Setup Environment & Test Data
|
|
$this->seed([
|
|
RoleSeeder::class,
|
|
\Database\Seeders\SamplePsgcSeeder::class,
|
|
\Database\Seeders\SampleDropOffPointsSeeder::class,
|
|
\Database\Seeders\SampleDumpsitesSeeder::class,
|
|
]);
|
|
|
|
$admin = User::factory()->create(['role' => User::ROLE_ADMIN, 'status' => 'active']);
|
|
$driver = User::factory()->create(['role' => User::ROLE_DRIVER, 'status' => 'active']);
|
|
$scanner = User::factory()->create(['role' => User::ROLE_SCANNER, 'status' => 'active']);
|
|
|
|
$dumpsite = Dumpsite::first();
|
|
$dropOffPoint = DropOffPoint::first();
|
|
|
|
$route = Route::create([
|
|
'name' => 'E2E Test Route',
|
|
'code' => 'RT-E2E',
|
|
'default_dumpsite_id' => $dumpsite->id,
|
|
'status' => 'active',
|
|
]);
|
|
|
|
$route->stops()->create([
|
|
'drop_off_point_id' => $dropOffPoint->id,
|
|
'sequence' => 1,
|
|
]);
|
|
|
|
$team = CollectionTeam::create([
|
|
'name' => 'E2E Team',
|
|
'driver_id' => $driver->id,
|
|
'scanner_id' => $scanner->id,
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// Set up a Resident QR Code
|
|
$resident = User::factory()->create(['role' => User::ROLE_RESIDENT, 'status' => 'active']);
|
|
$batch = \App\Models\QrCodeBatch::create([
|
|
'batch_number' => 'BATCH-E2E-1',
|
|
'status' => 'active',
|
|
'quantity' => 10,
|
|
]);
|
|
$qr = QrCode::create([
|
|
'serial' => 'E2E-TEST-QR-001',
|
|
'assigned_to_user_id' => $resident->id,
|
|
'batch_id' => $batch->id,
|
|
'status' => 'active',
|
|
]);
|
|
|
|
// ==========================================
|
|
// 2. Admin Schedules a Trip
|
|
// ==========================================
|
|
$response = $this->actingAs($admin)->postJson('/api/v1/admin/trips', [
|
|
'route_id' => $route->id,
|
|
'team_id' => $team->id,
|
|
'scheduled_date' => now()->toDateString(),
|
|
]);
|
|
|
|
$response->assertStatus(201);
|
|
$tripUuid = $response->json('data.id');
|
|
$this->assertNotNull($tripUuid);
|
|
|
|
$trip = Trip::where('uuid', $tripUuid)->first();
|
|
$this->assertEquals(Trip::STATUS_SCHEDULED, $trip->status);
|
|
|
|
// ==========================================
|
|
// 3. Driver Starts the Trip
|
|
// ==========================================
|
|
$response = $this->actingAs($driver)->postJson("/api/v1/driver/trips/{$tripUuid}/start");
|
|
$response->assertStatus(200);
|
|
|
|
$trip->refresh();
|
|
$this->assertEquals(Trip::STATUS_IN_PROGRESS, $trip->status);
|
|
|
|
// Driver arrives at the first stop
|
|
$stop = $trip->stops()->first();
|
|
$response = $this->actingAs($driver)->postJson("/api/v1/driver/trips/{$tripUuid}/stops/{$stop->id}/arrive", [
|
|
'lat' => $dropOffPoint->coordinates->latitude,
|
|
'lng' => $dropOffPoint->coordinates->longitude,
|
|
]);
|
|
$response->assertStatus(200);
|
|
|
|
// ==========================================
|
|
// 4. Scanner Scans a Household QR Code
|
|
// ==========================================
|
|
$response = $this->actingAs($scanner)->postJson('/api/v1/scanner/scan', [
|
|
'serial' => $qr->serial,
|
|
'drop_off_point_id' => $dropOffPoint->id,
|
|
'lat' => $dropOffPoint->coordinates->latitude,
|
|
'lng' => $dropOffPoint->coordinates->longitude,
|
|
'trip_id' => $tripUuid,
|
|
'trip_stop_id' => $stop->id,
|
|
'weight_kg' => 5,
|
|
]);
|
|
$response->assertStatus(200);
|
|
|
|
// Driver departs from the stop
|
|
$response = $this->actingAs($driver)->postJson("/api/v1/driver/trips/{$tripUuid}/stops/{$stop->id}/depart", [
|
|
'lat' => $dropOffPoint->coordinates->latitude,
|
|
'lng' => $dropOffPoint->coordinates->longitude,
|
|
]);
|
|
$response->assertStatus(200);
|
|
|
|
// ==========================================
|
|
// 5. Driver Arrives at Dumpsite and Completes
|
|
// ==========================================
|
|
$response = $this->actingAs($driver)->postJson("/api/v1/driver/trips/{$tripUuid}/arrive-dumpsite", [
|
|
'lat' => 14.1,
|
|
'lng' => 121.1,
|
|
'dumpsite_id' => $dumpsite->id,
|
|
'override_geofence' => true,
|
|
]);
|
|
$response->assertStatus(200);
|
|
|
|
$response = $this->actingAs($driver)->postJson("/api/v1/driver/trips/{$tripUuid}/release-load", [
|
|
'dumpsite_id' => $dumpsite->id,
|
|
'weight_kg' => 1000,
|
|
'override_geofence' => true,
|
|
]);
|
|
$response->assertStatus(201);
|
|
|
|
$response = $this->actingAs($driver)->postJson("/api/v1/driver/trips/{$tripUuid}/complete", [
|
|
'lat' => 14.1,
|
|
'lng' => 121.1,
|
|
'override_geofence' => true,
|
|
]);
|
|
$response->assertStatus(200);
|
|
|
|
// Verify Final State
|
|
$trip->refresh();
|
|
$this->assertEquals(Trip::STATUS_COMPLETED, $trip->status);
|
|
$this->assertEquals(1000, $trip->total_load_kg);
|
|
}
|
|
}
|