- Rewrite DashboardController with cached role-scoped KPI aggregation (Cache::remember, 5-min TTL, Declaration::forUser scope) - Create StatCard.vue component with CVA status variants and a11y - Rewrite Dashboard.vue with 4-column KPI grid + urgent declarations table - Add mise_en_demeure status to DeclarationStatus enum with transitions - Exclude termine, mise_en_demeure, ferme from dashboard queries - Set deadline proximity red threshold to ≤5 days - Add abort(404) for non-member workspace access per architecture - Fix null-safe client access for soft-deleted clients - Fix hardcoded routes with Wayfinder type-safe imports - Fix DashboardProps.stats type to allow null - Add aria-pressed to StatCard for accessibility - Install shadcn-vue table component (11 files) - Add 11 Pest feature tests + 3 mise_en_demeure transition tests - Fix DeclarationFactory eager workspace creation causing slug collisions - 196 tests pass, 836 assertions, zero regressions
141 lines
5.5 KiB
PHP
141 lines
5.5 KiB
PHP
<?php
|
|
|
|
use App\Enums\DeclarationStatus;
|
|
use App\Models\Declaration;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
test('valid transition: created to en_cours', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('en_cours');
|
|
});
|
|
|
|
test('valid transition: en_cours to en_attente_client', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::EnAttenteClient]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('en_attente_client');
|
|
});
|
|
|
|
test('valid transition: en_attente_client to en_cours', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
$declaration->update(['status' => DeclarationStatus::EnAttenteClient]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('en_cours');
|
|
});
|
|
|
|
test('valid transition: en_cours to termine', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::Termine]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('termine');
|
|
});
|
|
|
|
test('valid transition: termine to ferme', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
$declaration->update(['status' => DeclarationStatus::Termine]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::Ferme]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('ferme');
|
|
});
|
|
|
|
test('valid transition: en_attente_client to mise_en_demeure', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
$declaration->update(['status' => DeclarationStatus::EnAttenteClient]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::MiseEnDemeure]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('mise_en_demeure');
|
|
});
|
|
|
|
test('valid transition: mise_en_demeure to en_cours', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
$declaration->update(['status' => DeclarationStatus::EnAttenteClient]);
|
|
$declaration->update(['status' => DeclarationStatus::MiseEnDemeure]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('en_cours');
|
|
});
|
|
|
|
test('valid transition: mise_en_demeure to ferme', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
$declaration->update(['status' => DeclarationStatus::EnAttenteClient]);
|
|
$declaration->update(['status' => DeclarationStatus::MiseEnDemeure]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::Ferme]);
|
|
|
|
expect($declaration->fresh()->status->value)->toBe('ferme');
|
|
});
|
|
|
|
test('invalid transition: created to ferme throws validation exception', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::Ferme]);
|
|
})->throws(ValidationException::class);
|
|
|
|
test('invalid transition: created to termine throws validation exception', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
|
|
$declaration->update(['status' => DeclarationStatus::Termine]);
|
|
})->throws(ValidationException::class);
|
|
|
|
test('auto-archive: ferme status sets archived_at', function () {
|
|
$declaration = Declaration::factory()->create(['status' => DeclarationStatus::Created]);
|
|
$declaration->update(['status' => DeclarationStatus::EnCours]);
|
|
$declaration->update(['status' => DeclarationStatus::Termine]);
|
|
|
|
expect($declaration->fresh()->archived_at)->toBeNull();
|
|
|
|
$declaration->update(['status' => DeclarationStatus::Ferme]);
|
|
|
|
$fresh = $declaration->fresh();
|
|
expect($fresh->archived_at)->not->toBeNull();
|
|
});
|
|
|
|
test('scope active excludes archived declarations', function () {
|
|
$active = Declaration::factory()->create([
|
|
'status' => DeclarationStatus::Created,
|
|
'archived_at' => null,
|
|
]);
|
|
$archived = Declaration::factory()->create([
|
|
'status' => DeclarationStatus::Created,
|
|
'archived_at' => now(),
|
|
]);
|
|
|
|
$activeIds = Declaration::active()->pluck('id')->all();
|
|
|
|
expect($activeIds)->toContain($active->id);
|
|
expect($activeIds)->not->toContain($archived->id);
|
|
});
|
|
|
|
test('scope archived includes only archived declarations', function () {
|
|
$active = Declaration::factory()->create([
|
|
'status' => DeclarationStatus::Created,
|
|
'archived_at' => null,
|
|
]);
|
|
$archived = Declaration::factory()->create([
|
|
'status' => DeclarationStatus::Created,
|
|
'archived_at' => now(),
|
|
]);
|
|
|
|
$archivedIds = Declaration::archived()->pluck('id')->all();
|
|
|
|
expect($archivedIds)->toContain($archived->id);
|
|
expect($archivedIds)->not->toContain($active->id);
|
|
});
|