317 lines
10 KiB
PHP
317 lines
10 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
use App\Enums\DeclarationStatus;
|
||
|
|
use App\Models\Client;
|
||
|
|
use App\Models\Declaration;
|
||
|
|
use App\Models\User;
|
||
|
|
use App\Models\Workspace;
|
||
|
|
use Illuminate\Support\Facades\Cache;
|
||
|
|
|
||
|
|
function setupWorkerWorkspace(): array
|
||
|
|
{
|
||
|
|
$worker = User::factory()->create();
|
||
|
|
$workspace = Workspace::factory()->create();
|
||
|
|
$workspace->users()->attach($worker->id, ['role' => 'worker']);
|
||
|
|
$client = Client::factory()->create(['workspace_id' => $workspace->id]);
|
||
|
|
session(['current_workspace_id' => $workspace->id]);
|
||
|
|
|
||
|
|
return [$worker, $workspace, $client];
|
||
|
|
}
|
||
|
|
|
||
|
|
test('worker sees only their assigned declarations in kpi counts', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
$otherUser = User::factory()->create();
|
||
|
|
$workspace->users()->attach($otherUser->id, ['role' => 'worker']);
|
||
|
|
|
||
|
|
// Assigned to this worker — overdue
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $worker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(3),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assigned to this worker — due this week
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $worker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->addDays(2),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assigned to this worker — en attente client
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $worker->id,
|
||
|
|
'status' => DeclarationStatus::EnAttenteClient,
|
||
|
|
'due_date' => now()->addDays(10),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assigned to OTHER worker (should NOT count)
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $otherUser->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(1),
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->where('stats.overdue', 1)
|
||
|
|
->where('stats.dueThisWeek', 1)
|
||
|
|
->where('stats.enAttenteClient', 1)
|
||
|
|
->where('stats.enCours', 2)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('worker does not see declarations assigned to other team members in kpi counts', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
$otherWorker = User::factory()->create();
|
||
|
|
$workspace->users()->attach($otherWorker->id, ['role' => 'worker']);
|
||
|
|
|
||
|
|
// Only assigned to other worker
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $otherWorker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(5),
|
||
|
|
]);
|
||
|
|
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $otherWorker->id,
|
||
|
|
'status' => DeclarationStatus::EnAttenteClient,
|
||
|
|
'due_date' => now()->addDays(2),
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->where('stats.overdue', 0)
|
||
|
|
->where('stats.dueThisWeek', 0)
|
||
|
|
->where('stats.enAttenteClient', 0)
|
||
|
|
->where('stats.enCours', 0)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('worker sees only their assigned declarations in the urgent declarations table', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
$otherWorker = User::factory()->create();
|
||
|
|
$workspace->users()->attach($otherWorker->id, ['role' => 'worker']);
|
||
|
|
|
||
|
|
// Assigned to this worker
|
||
|
|
$myDeclaration = Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $worker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->addDays(2),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Assigned to other worker
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $otherWorker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->addDays(1),
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->has('declarations', 1)
|
||
|
|
->where('declarations.0.id', $myDeclaration->id)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('worker sees only their assigned declarations in priority alerts', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
$otherWorker = User::factory()->create();
|
||
|
|
$workspace->users()->attach($otherWorker->id, ['role' => 'worker']);
|
||
|
|
|
||
|
|
// Overdue declaration assigned to this worker (generates critical alert)
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $worker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(5),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Overdue declaration assigned to other worker (should NOT appear)
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $otherWorker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(3),
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->has('alerts', 1)
|
||
|
|
->where('alerts.0.severity', 'critical')
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('worker dashboard returns isWorker true in inertia props', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->where('isWorker', true)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('worker with no assigned declarations gets zero counts and empty arrays', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
// Declarations exist but assigned to someone else
|
||
|
|
$otherUser = User::factory()->create();
|
||
|
|
$workspace->users()->attach($otherUser->id, ['role' => 'worker']);
|
||
|
|
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $otherUser->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(1),
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->where('stats.overdue', 0)
|
||
|
|
->where('stats.dueThisWeek', 0)
|
||
|
|
->where('stats.enAttenteClient', 0)
|
||
|
|
->where('stats.enCours', 0)
|
||
|
|
->where('declarations', [])
|
||
|
|
->where('alerts', [])
|
||
|
|
->where('isWorker', true)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('worker stat card hrefs include assignee scoping param', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->has('statCards', 4)
|
||
|
|
->where('statCards.0.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
|
||
|
|
->where('statCards.1.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
|
||
|
|
->where('statCards.2.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
|
||
|
|
->where('statCards.3.href', fn ($href) => str_contains($href, 'assignee='.$worker->id))
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('owner and manager dashboard returns isWorker false', function () {
|
||
|
|
$ownerUser = User::factory()->create();
|
||
|
|
$managerUser = User::factory()->create();
|
||
|
|
$workspace = Workspace::factory()->create();
|
||
|
|
$workspace->users()->attach($ownerUser->id, ['role' => 'owner']);
|
||
|
|
$workspace->users()->attach($managerUser->id, ['role' => 'manager']);
|
||
|
|
session(['current_workspace_id' => $workspace->id]);
|
||
|
|
|
||
|
|
// Owner
|
||
|
|
$this->actingAs($ownerUser);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->where('isWorker', false)
|
||
|
|
);
|
||
|
|
|
||
|
|
// Manager
|
||
|
|
$this->actingAs($managerUser);
|
||
|
|
$response = $this->get(route('dashboard'));
|
||
|
|
$response->assertOk();
|
||
|
|
$response->assertInertia(fn ($page) => $page
|
||
|
|
->component('Dashboard')
|
||
|
|
->where('isWorker', false)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('cached data is scoped per user with worker cache key including user id', function () {
|
||
|
|
[$worker, $workspace, $client] = setupWorkerWorkspace();
|
||
|
|
|
||
|
|
$otherWorker = User::factory()->create();
|
||
|
|
$workspace->users()->attach($otherWorker->id, ['role' => 'worker']);
|
||
|
|
|
||
|
|
// Declaration assigned to first worker
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $worker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(1),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// Declaration assigned to second worker
|
||
|
|
Declaration::factory()->create([
|
||
|
|
'workspace_id' => $workspace->id,
|
||
|
|
'client_id' => $client->id,
|
||
|
|
'assigned_to' => $otherWorker->id,
|
||
|
|
'status' => DeclarationStatus::EnCours,
|
||
|
|
'due_date' => now()->subDays(2),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// First worker request
|
||
|
|
$this->actingAs($worker);
|
||
|
|
$this->get(route('dashboard'))->assertOk();
|
||
|
|
|
||
|
|
$workerCacheKey = "dashboard:{$workspace->id}:{$worker->id}";
|
||
|
|
$otherCacheKey = "dashboard:{$workspace->id}:{$otherWorker->id}";
|
||
|
|
|
||
|
|
expect(Cache::has($workerCacheKey))->toBeTrue();
|
||
|
|
expect(Cache::has($otherCacheKey))->toBeFalse();
|
||
|
|
|
||
|
|
$workerCached = Cache::get($workerCacheKey);
|
||
|
|
expect($workerCached['overdue'])->toBe(1)
|
||
|
|
->and($workerCached['enCours'])->toBe(1);
|
||
|
|
|
||
|
|
// Second worker request
|
||
|
|
$this->actingAs($otherWorker);
|
||
|
|
$this->get(route('dashboard'))->assertOk();
|
||
|
|
|
||
|
|
expect(Cache::has($otherCacheKey))->toBeTrue();
|
||
|
|
$otherCached = Cache::get($otherCacheKey);
|
||
|
|
expect($otherCached['overdue'])->toBe(1)
|
||
|
|
->and($otherCached['enCours'])->toBe(1);
|
||
|
|
});
|