Dodanie floty do profila pracownika
This commit is contained in:
parent
4c9142d6ad
commit
cd1234a118
@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use App\Models\Vehicle;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
use Spatie\Permission\Models\Role;
|
use Spatie\Permission\Models\Role;
|
||||||
|
|
||||||
@ -38,13 +39,23 @@ class DashboardController extends Controller
|
|||||||
->take(10)
|
->take(10)
|
||||||
->values();
|
->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(
|
return view('dashboard', compact(
|
||||||
'totalUsers',
|
'totalUsers',
|
||||||
'adminCount',
|
'adminCount',
|
||||||
'managerCount',
|
'managerCount',
|
||||||
'workerCount',
|
'workerCount',
|
||||||
'recentUsers',
|
'recentUsers',
|
||||||
'lowestAdvanceBalances'
|
'lowestAdvanceBalances',
|
||||||
|
'vehiclesDueSoon'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,11 @@ class User extends Authenticatable
|
|||||||
return $this->hasMany(Advance::class);
|
return $this->hasMany(Advance::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function vehicles(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Vehicle::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function advanceBalance(): HasOne
|
public function advanceBalance(): HasOne
|
||||||
{
|
{
|
||||||
return $this->hasOne(UserAdvanceBalance::class);
|
return $this->hasOne(UserAdvanceBalance::class);
|
||||||
|
|||||||
60
database/seeders/AdvanceSeeder.php
Normal file
60
database/seeders/AdvanceSeeder.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Advance;
|
||||||
|
use App\Models\AdvanceType;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class AdvanceSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$users = User::query()->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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -53,6 +53,7 @@ class DatabaseSeeder extends Seeder
|
|||||||
$this->call([
|
$this->call([
|
||||||
AdvanceTypeSeeder::class,
|
AdvanceTypeSeeder::class,
|
||||||
UserSeeder::class,
|
UserSeeder::class,
|
||||||
|
AdvanceSeeder::class,
|
||||||
VehicleSeeder::class,
|
VehicleSeeder::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,6 +133,58 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{-- Samochody do uwagi --}}
|
||||||
|
<div class="bg-amber-50 dark:bg-amber-900/20 p-6 rounded-lg shadow-sm border border-amber-200 dark:border-amber-800/60 lg:col-span-3">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h3 class="text-lg font-semibold text-amber-900 dark:text-amber-200">
|
||||||
|
Samochody do uwagi
|
||||||
|
</h3>
|
||||||
|
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold bg-amber-100 dark:bg-amber-800/40 text-amber-800 dark:text-amber-200">
|
||||||
|
do 14 dni
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if(($vehiclesDueSoon ?? collect())->isNotEmpty())
|
||||||
|
<div class="space-y-3">
|
||||||
|
@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
|
||||||
|
|
||||||
|
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-2 rounded-lg border border-amber-200 dark:border-amber-700/60 bg-white/70 dark:bg-gray-900/30 p-4">
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold text-gray-900 dark:text-white">
|
||||||
|
{{ $vehicle->brand }} {{ $vehicle->model ?? '' }}
|
||||||
|
</p>
|
||||||
|
<p class="text-sm text-gray-600 dark:text-gray-300">
|
||||||
|
{{ $vehicle->registration_number }} · {{ $vehicle->user?->name }} {{ $vehicle->user?->surname }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap gap-2 text-xs font-medium">
|
||||||
|
@if($ocDue)
|
||||||
|
<span class="inline-flex items-center px-2.5 py-1 rounded-full bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-200">
|
||||||
|
OC: {{ $vehicle->oc_expiry_date->format('d.m.Y') }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($inspectionDue)
|
||||||
|
<span class="inline-flex items-center px-2.5 py-1 rounded-full bg-orange-100 dark:bg-orange-900/40 text-orange-700 dark:text-orange-200">
|
||||||
|
Przegląd: {{ $vehicle->technical_inspection_date->format('d.m.Y') }}
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@else
|
||||||
|
<p class="text-sm text-amber-800 dark:text-amber-200">
|
||||||
|
Brak pojazdów z terminem OC lub przeglądu w najbliższych 14 dniach.
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- Najniższy bilans zaliczek --}}
|
{{-- Najniższy bilans zaliczek --}}
|
||||||
<div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700/50 lg:col-span-3">
|
<div class="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-sm border border-gray-200 dark:border-gray-700/50 lg:col-span-3">
|
||||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">
|
||||||
|
|||||||
@ -85,6 +85,43 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="employee-profile-info bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg border border-gray-200 dark:border-gray-700/50 p-6">
|
||||||
|
<h4 class="text-lg font-semibold mb-4">Przypisany pojazd</h4>
|
||||||
|
|
||||||
|
@php($assignedVehicle = $user->vehicles()->first())
|
||||||
|
|
||||||
|
@if($assignedVehicle)
|
||||||
|
<dl class="space-y-3 text-sm">
|
||||||
|
<div>
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Samochód</dt>
|
||||||
|
<dd class="font-medium text-gray-900 dark:text-white">{{ $assignedVehicle->brand }} {{ $assignedVehicle->model }}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Nr rejestracyjny</dt>
|
||||||
|
<dd class="font-medium text-gray-900 dark:text-white">{{ $assignedVehicle->registration_number }}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Status</dt>
|
||||||
|
<dd class="font-medium text-gray-900 dark:text-white">{{ $assignedVehicle->status }}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">OC</dt>
|
||||||
|
<dd class="font-medium text-gray-900 dark:text-white">{{ $assignedVehicle->oc_expiry_date?->format('d.m.Y') ?? '—' }}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Przegląd</dt>
|
||||||
|
<dd class="font-medium text-gray-900 dark:text-white">{{ $assignedVehicle->technical_inspection_date?->format('d.m.Y') ?? '—' }}</dd>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<dt class="text-gray-500 dark:text-gray-400">Ubezpieczenie</dt>
|
||||||
|
<dd class="font-medium text-gray-900 dark:text-white">{{ $assignedVehicle->insurance_provider ?? '—' }}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
@else
|
||||||
|
<p class="text-sm text-gray-500 dark:text-gray-400">Brak przypisanego pojazdu.</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="employee-profile-finance lg:col-span-2 bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg border border-gray-200 dark:border-gray-700/50 p-6">
|
<div class="employee-profile-finance lg:col-span-2 bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg border border-gray-200 dark:border-gray-700/50 p-6">
|
||||||
<h4 class="text-lg font-semibold mb-4">Podsumowanie finansowe</h4>
|
<h4 class="text-lg font-semibold mb-4">Podsumowanie finansowe</h4>
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,14 @@ function userWithAdvanceAccess(string $roleName = 'pracownik'): User
|
|||||||
return $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 () {
|
test('employee sees only own advances', function () {
|
||||||
$employee = userWithAdvanceAccess();
|
$employee = userWithAdvanceAccess();
|
||||||
$otherUser = User::factory()->create();
|
$otherUser = User::factory()->create();
|
||||||
|
|||||||
@ -129,3 +129,81 @@ test('manager can delete a vehicle', function () {
|
|||||||
$response->assertRedirect(route('flota'));
|
$response->assertRedirect(route('flota'));
|
||||||
$this->assertDatabaseMissing('vehicles', ['id' => $vehicle->id]);
|
$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');
|
||||||
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user