diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index 8b751e6..8435b62 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Models\User;
+use App\Models\Vehicle;
use Illuminate\View\View;
use Spatie\Permission\Models\Role;
@@ -38,13 +39,23 @@ class DashboardController extends Controller
->take(10)
->values();
+ $vehiclesDueSoon = Vehicle::with('user')
+ ->where(function ($query) {
+ $query->whereBetween('oc_expiry_date', [now()->startOfDay(), now()->addDays(14)->endOfDay()])
+ ->orWhereBetween('technical_inspection_date', [now()->startOfDay(), now()->addDays(14)->endOfDay()]);
+ })
+ ->orderBy('oc_expiry_date')
+ ->orderBy('technical_inspection_date')
+ ->get();
+
return view('dashboard', compact(
'totalUsers',
'adminCount',
'managerCount',
'workerCount',
'recentUsers',
- 'lowestAdvanceBalances'
+ 'lowestAdvanceBalances',
+ 'vehiclesDueSoon'
));
}
}
diff --git a/app/Models/User.php b/app/Models/User.php
index 1a05cb0..bf50f79 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -61,6 +61,11 @@ class User extends Authenticatable
return $this->hasMany(Advance::class);
}
+ public function vehicles(): HasMany
+ {
+ return $this->hasMany(Vehicle::class);
+ }
+
public function advanceBalance(): HasOne
{
return $this->hasOne(UserAdvanceBalance::class);
diff --git a/database/seeders/AdvanceSeeder.php b/database/seeders/AdvanceSeeder.php
new file mode 100644
index 0000000..8ecff9f
--- /dev/null
+++ b/database/seeders/AdvanceSeeder.php
@@ -0,0 +1,60 @@
+orderBy('id')->pluck('id')->all();
+ $types = AdvanceType::query()->pluck('id', 'name')->all();
+
+ if (empty($users) || empty($types)) {
+ return;
+ }
+
+ $entries = [
+ ['user_index' => 0, 'type' => 'Paliwo', 'amount' => 180.50, 'days_ago' => 1],
+ ['user_index' => 1, 'type' => 'Hotel', 'amount' => 240.00, 'days_ago' => 2],
+ ['user_index' => 2, 'type' => 'Wpłata', 'amount' => 500.00, 'days_ago' => 3],
+ ['user_index' => 0, 'type' => 'Paliwo', 'amount' => 95.20, 'days_ago' => 6],
+ ['user_index' => 1, 'type' => 'Hotel', 'amount' => 310.40, 'days_ago' => 8],
+ ['user_index' => 3, 'type' => 'Paliwo', 'amount' => 150.10, 'days_ago' => 9],
+ ['user_index' => 4, 'type' => 'Wpłata', 'amount' => 750.00, 'days_ago' => 10],
+ ['user_index' => 2, 'type' => 'Hotel', 'amount' => 420.00, 'days_ago' => 12],
+ ['user_index' => 5, 'type' => 'Paliwo', 'amount' => 205.30, 'days_ago' => 14],
+ ['user_index' => 6, 'type' => 'Wpłata', 'amount' => 600.00, 'days_ago' => 15],
+ ['user_index' => 0, 'type' => 'Hotel', 'amount' => 280.00, 'days_ago' => 17],
+ ['user_index' => 1, 'type' => 'Paliwo', 'amount' => 120.00, 'days_ago' => 18],
+ ['user_index' => 3, 'type' => 'Wpłata', 'amount' => 900.00, 'days_ago' => 20],
+ ['user_index' => 4, 'type' => 'Hotel', 'amount' => 360.75, 'days_ago' => 22],
+ ['user_index' => 5, 'type' => 'Paliwo', 'amount' => 175.25, 'days_ago' => 24],
+ ['user_index' => 6, 'type' => 'Wpłata', 'amount' => 850.00, 'days_ago' => 26],
+ ['user_index' => 2, 'type' => 'Paliwo', 'amount' => 165.15, 'days_ago' => 28],
+ ['user_index' => 0, 'type' => 'Wpłata', 'amount' => 1200.00, 'days_ago' => 29],
+ ['user_index' => 1, 'type' => 'Hotel', 'amount' => 540.20, 'days_ago' => 30],
+ ['user_index' => 3, 'type' => 'Paliwo', 'amount' => 210.45, 'days_ago' => 33],
+ ];
+
+ foreach ($entries as $index => $entry) {
+ $userId = $users[$entry['user_index']] ?? $users[0];
+ $typeId = $types[$entry['type']] ?? null;
+
+ if (! $typeId) {
+ continue;
+ }
+
+ Advance::create([
+ 'date' => now()->subDays($entry['days_ago'])->toDateString(),
+ 'user_id' => $userId,
+ 'amount' => $entry['amount'],
+ 'advance_type_id' => $typeId,
+ ]);
+ }
+ }
+}
diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php
index c8a8733..39018cd 100644
--- a/database/seeders/DatabaseSeeder.php
+++ b/database/seeders/DatabaseSeeder.php
@@ -53,6 +53,7 @@ class DatabaseSeeder extends Seeder
$this->call([
AdvanceTypeSeeder::class,
UserSeeder::class,
+ AdvanceSeeder::class,
VehicleSeeder::class,
]);
}
diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php
index 4ca0485..fe3115f 100644
--- a/resources/views/dashboard.blade.php
+++ b/resources/views/dashboard.blade.php
@@ -133,6 +133,58 @@
+ {{-- Samochody do uwagi --}}
+
+
+
+ Samochody do uwagi
+
+
+ do 14 dni
+
+
+
+ @if(($vehiclesDueSoon ?? collect())->isNotEmpty())
+
+ @foreach($vehiclesDueSoon as $vehicle)
+ @php
+ $ocDue = $vehicle->oc_expiry_date && $vehicle->oc_expiry_date->between(now()->startOfDay(), now()->addDays(14)->endOfDay());
+ $inspectionDue = $vehicle->technical_inspection_date && $vehicle->technical_inspection_date->between(now()->startOfDay(), now()->addDays(14)->endOfDay());
+ @endphp
+
+
+
+
+ {{ $vehicle->brand }} {{ $vehicle->model ?? '' }}
+
+
+ {{ $vehicle->registration_number }} · {{ $vehicle->user?->name }} {{ $vehicle->user?->surname }}
+
+
+
+
+ @if($ocDue)
+
+ OC: {{ $vehicle->oc_expiry_date->format('d.m.Y') }}
+
+ @endif
+
+ @if($inspectionDue)
+
+ Przegląd: {{ $vehicle->technical_inspection_date->format('d.m.Y') }}
+
+ @endif
+
+
+ @endforeach
+
+ @else
+
+ Brak pojazdów z terminem OC lub przeglądu w najbliższych 14 dniach.
+
+ @endif
+
+
{{-- Najniższy bilans zaliczek --}}
diff --git a/resources/views/users/show.blade.php b/resources/views/users/show.blade.php
index e913997..171e194 100644
--- a/resources/views/users/show.blade.php
+++ b/resources/views/users/show.blade.php
@@ -85,6 +85,43 @@
+
+
Przypisany pojazd
+
+ @php($assignedVehicle = $user->vehicles()->first())
+
+ @if($assignedVehicle)
+
+
+
- Samochód
+ - {{ $assignedVehicle->brand }} {{ $assignedVehicle->model }}
+
+
+
- Nr rejestracyjny
+ - {{ $assignedVehicle->registration_number }}
+
+
+
- Status
+ - {{ $assignedVehicle->status }}
+
+
+
- OC
+ - {{ $assignedVehicle->oc_expiry_date?->format('d.m.Y') ?? '—' }}
+
+
+
- Przegląd
+ - {{ $assignedVehicle->technical_inspection_date?->format('d.m.Y') ?? '—' }}
+
+
+
- Ubezpieczenie
+ - {{ $assignedVehicle->insurance_provider ?? '—' }}
+
+
+ @else
+
Brak przypisanego pojazdu.
+ @endif
+
+
Podsumowanie finansowe
diff --git a/tests/Feature/AdvanceTest.php b/tests/Feature/AdvanceTest.php
index ae36149..fdcaf99 100644
--- a/tests/Feature/AdvanceTest.php
+++ b/tests/Feature/AdvanceTest.php
@@ -20,6 +20,14 @@ function userWithAdvanceAccess(string $roleName = 'pracownik'): User
return $user;
}
+test('database seeder creates 20 sample advances', function () {
+ $this->seed();
+
+ $seededAdvances = Advance::count();
+
+ expect($seededAdvances)->toBe(20);
+});
+
test('employee sees only own advances', function () {
$employee = userWithAdvanceAccess();
$otherUser = User::factory()->create();
diff --git a/tests/Feature/VehicleTest.php b/tests/Feature/VehicleTest.php
index 498ff37..b5119eb 100644
--- a/tests/Feature/VehicleTest.php
+++ b/tests/Feature/VehicleTest.php
@@ -129,3 +129,81 @@ test('manager can delete a vehicle', function () {
$response->assertRedirect(route('flota'));
$this->assertDatabaseMissing('vehicles', ['id' => $vehicle->id]);
});
+
+test('dashboard shows vehicles with upcoming technical inspection or oc expiry within 14 days', function () {
+ $manager = createFleetUser('kierownik');
+ $user = User::factory()->create();
+
+ $urgentVehicle = Vehicle::create([
+ 'brand' => 'Toyota',
+ 'model' => 'Corolla',
+ 'registration_number' => 'DW1234A',
+ 'user_id' => $user->id,
+ 'year' => 2021,
+ 'purchase_date' => '2021-05-12',
+ 'oc_expiry_date' => now()->addDays(10)->toDateString(),
+ 'oil_change_km' => 12000,
+ 'insurance_provider' => 'PZU',
+ 'technical_inspection_date' => now()->addDays(20)->toDateString(),
+ 'mileage_km' => 95000,
+ 'status' => 'używany',
+ ]);
+
+ $safeVehicle = Vehicle::create([
+ 'brand' => 'Ford',
+ 'model' => 'Transit',
+ 'registration_number' => 'WA9876Z',
+ 'user_id' => $user->id,
+ 'year' => 2019,
+ 'purchase_date' => '2019-07-20',
+ 'oc_expiry_date' => now()->addDays(30)->toDateString(),
+ 'oil_change_km' => 8000,
+ 'insurance_provider' => 'Warta',
+ 'technical_inspection_date' => now()->addDays(40)->toDateString(),
+ 'mileage_km' => 175000,
+ 'status' => 'aktywny',
+ ]);
+
+ $response = $this->actingAs($manager)->get(route('dashboard'));
+
+ $response->assertOk();
+ $response->assertSee('Samochody do uwagi');
+ $response->assertSee($urgentVehicle->brand);
+ $response->assertSee('OC');
+ $response->assertDontSee($safeVehicle->brand);
+});
+
+test('employee profile shows assigned vehicle with expire dates and insurance details', function () {
+ Permission::firstOrCreate(['name' => 'users_access']);
+
+ $manager = User::factory()->create();
+ $managerRole = Role::firstOrCreate(['name' => 'kierownik']);
+ $managerRole->givePermissionTo(['users_access', 'flota_access']);
+ $manager->assignRole($managerRole);
+
+ $user = User::factory()->create();
+
+ $vehicle = Vehicle::create([
+ 'brand' => 'BMW',
+ 'model' => 'X5',
+ 'registration_number' => 'PO1111A',
+ 'user_id' => $user->id,
+ 'year' => 2022,
+ 'purchase_date' => '2022-02-10',
+ 'oc_expiry_date' => now()->addDays(9)->toDateString(),
+ 'oil_change_km' => 12000,
+ 'insurance_provider' => 'PZU',
+ 'technical_inspection_date' => now()->addDays(12)->toDateString(),
+ 'mileage_km' => 55000,
+ 'status' => 'używany',
+ ]);
+
+ $response = $this->actingAs($manager)->get(route('users.show', $user));
+
+ $response->assertOk();
+ $response->assertSee('Przypisany pojazd');
+ $response->assertSee($vehicle->brand);
+ $response->assertSee('PZU');
+ $response->assertSee('OC');
+ $response->assertSee('Przegląd');
+});