Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions app/Concerns/Auditable.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Concerns;

use App\Models\AuditLog;
use Illuminate\Database\Eloquent\Model;

/**
* Enregistre automatiquement les créations / modifications / suppressions
Expand All @@ -16,9 +15,9 @@ trait Auditable
{
public static function bootAuditable(): void
{
static::created(fn (Model $model) => $model->recordAudit('created', null, $model->auditableAttributes()));
static::created(fn (self $model) => $model->recordAudit('created', null, $model->auditableAttributes()));

static::updated(function (Model $model): void {
static::updated(function (self $model): void {
$changed = array_keys($model->getChanges());
$keys = array_diff($changed, $model->auditExcluded());
if ($keys === []) {
Expand All @@ -31,7 +30,7 @@ public static function bootAuditable(): void
$model->recordAudit('updated', $old, $new);
});

static::deleted(fn (Model $model) => $model->recordAudit('deleted', $model->auditableAttributes(), null));
static::deleted(fn (self $model) => $model->recordAudit('deleted', $model->auditableAttributes(), null));
}

/** Champs exclus du journal (secrets et bruit). */
Expand Down
53 changes: 21 additions & 32 deletions app/Console/Commands/GenerateStudentMatricule.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
namespace App\Console\Commands;

use App\Models\Student;
use App\Services\MatriculeService;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Collection;

class GenerateStudentMatricule extends Command
{
Expand All @@ -13,10 +13,10 @@ class GenerateStudentMatricule extends Command
*
* @var string
*/
protected $signature = 'matricule:generate-student
protected $signature = 'matricule:generate-student
{--class-id= : ID de la classe}
{--all : Générer pour tous les élèves}
{--registration : Générer aussi les numéros d\'enregistrement}
{--matricule : Générer aussi les matricules des élèves}
{--force : Forcer la régénération}';

/**
Expand All @@ -31,10 +31,9 @@ class GenerateStudentMatricule extends Command
*/
public function handle(): int
{
$matriculeService = app(MatriculeService::class);
$withStudentMatricule = (bool) $this->option('matricule');

if ($this->option('all')) {
// Générer pour tous les élèves
$students = Student::all();

if ($students->isEmpty()) {
Expand All @@ -44,28 +43,7 @@ public function handle(): int
}

$this->info("Génération des matricules pour {$students->count()} élèves...");

$progressBar = $this->output->createProgressBar($students->count());
$progressBar->start();

foreach ($students as $student) {
// Générer matricule de l'utilisateur
if (! $student->user->natricule) {
$student->user->natricule = $student->user->generateMatricule();
$student->user->save();
}

// Générer numéro d'enregistrement
if (! $student->registration_number) {
$student->registration_number = $student->generateRegistrationNumber();
$student->save();
}

$progressBar->advance();
}

$progressBar->finish();
$this->newLine();
$this->backfillMatricules($students, $withStudentMatricule);
$this->info('✅ Matricules générés avec succès!');

return 0;
Expand All @@ -88,18 +66,32 @@ public function handle(): int
}

$this->info("Génération pour {$students->count()} élèves...");
$this->backfillMatricules($students, $withStudentMatricule);
$this->info('✅ Matricules générés avec succès!');

return 0;
}

/**
* Génère les matricules manquants pour un lot d'élèves.
*
* @param Collection<int, Student> $students
*/
private function backfillMatricules(Collection $students, bool $withStudentMatricule): void
{
$progressBar = $this->output->createProgressBar($students->count());
$progressBar->start();

foreach ($students as $student) {
// Matricule du compte utilisateur associé.
if (! $student->user->natricule) {
$student->user->natricule = $student->user->generateMatricule();
$student->user->save();
}

if (! $student->registration_number) {
$student->registration_number = $student->generateRegistrationNumber();
// Matricule de l'élève (optionnel, via --matricule).
if ($withStudentMatricule && empty($student->matricule)) {
$student->matricule = $student->generateMatricule();
$student->save();
}

Expand All @@ -108,8 +100,5 @@ public function handle(): int

$progressBar->finish();
$this->newLine();
$this->info('✅ Matricules générés avec succès!');

return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ public function statistics(Request $request): Response
$assignments = $selected
? $this->teacherAssignments($teacherId, $yearFilter)->map(fn ($a) => [
'id' => $a->id,
'subject' => $a->subject?->name ?? '—',
'classroom' => $a->classroom?->name ?? '—',
'subject' => $a->subject->name ?? '—',
'classroom' => $a->classroom->name ?? '—',
'active' => (bool) $a->active,
])
: collect();
Expand Down Expand Up @@ -143,7 +143,7 @@ public function exportStatistics(Request $request)
'assignments' => $this->teacherAssignments($teacher->id, $yearId),
])->setPaper('a4', 'portrait');

return $pdf->stream('affectations-'.Str::slug(trim($teacher->firstname.' '.$teacher->lastname).'-'.($year?->year ?? '')).'.pdf');
return $pdf->stream('affectations-'.Str::slug(trim($teacher->firstname.' '.$teacher->lastname).'-'.($year->year ?? '')).'.pdf');
}

/** Identifiant de l'année académique active (la plus récente marquée active). */
Expand All @@ -170,7 +170,7 @@ private function teacherAssignments(string $teacherId, string $yearId): Collecti
->where('teacher_id', $teacherId)
->where('academic_year_id', $yearId)
->get()
->sortBy(fn ($a) => ($a->subject?->name ?? '').' '.($a->classroom?->name ?? ''))
->sortBy(fn ($a) => ($a->subject->name ?? '').' '.($a->classroom->name ?? ''))
->values();
}

Expand Down
4 changes: 4 additions & 0 deletions app/Http/Controllers/Api/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ abstract class ApiController extends Controller
*/
protected function accessibleStudents(Request $request): Collection
{
// Ces routes API authentifient un élève ou un tuteur (gardes Sanctum
// dédiées), jamais le User par défaut supposé par l'analyse statique.
/** @var Student|Guardian|null $user */
$user = $request->user();

if ($user instanceof Student) {
Expand All @@ -38,6 +41,7 @@ protected function accessibleStudents(Request $request): Collection
*/
protected function resolveStudent(Request $request, string $studentId): Student
{
/** @var Student|Guardian|null $user */
$user = $request->user();

if ($user instanceof Student) {
Expand Down
6 changes: 5 additions & 1 deletion app/Http/Controllers/Api/V1/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public function login(LoginRequest $request): JsonResponse

public function me(Request $request): JsonResponse
{
// Portail parent/élève : le principal authentifié est un tuteur ou un élève.
/** @var Guardian|Student $user */
$user = $request->user();
$type = $user instanceof Guardian ? 'guardian' : 'student';

Expand All @@ -47,7 +49,9 @@ public function me(Request $request): JsonResponse

public function logout(Request $request): JsonResponse
{
$request->user()->currentAccessToken()->delete();
/** @var Guardian|Student $user */
$user = $request->user();
$user->currentAccessToken()->delete();

return response()->json(['message' => 'Déconnecté.']);
}
Expand Down
1 change: 1 addition & 0 deletions app/Http/Controllers/Api/V1/ChildrenController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function index(Request $request): AnonymousResourceCollection
{
$withActiveEnrollment = ['enrollments' => fn ($q) => $q->where('status', Enrollment::STATUS_ACTIVE)->with('classroom:id,name')];

/** @var Student|Guardian $user */
$user = $request->user();

if ($user instanceof Student) {
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Api/V1/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function index(Request $request): JsonResponse
'id' => $e->id,
'title' => $e->title,
'type' => $e->type,
'start_date' => $e->start_date?->format('Y-m-d'),
'start_date' => $e->start_date->format('Y-m-d'),
]);

return response()->json([
Expand Down
11 changes: 6 additions & 5 deletions app/Http/Controllers/Archives/ArchiveController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

class ArchiveController extends Controller
{
private const TYPES = ['student' => Student::class, 'classroom' => Classroom::class];

private function authorizeManage(Request $request): void
{
// Socle de sécurité : les routes portent déjà la permission fine (create/edit/
Expand Down Expand Up @@ -234,9 +232,12 @@ private function linkLabel(ArchivedDocument $d): ?string
return null;
}

return match ($d->documentable_type) {
Student::class => 'Élève : '.$d->documentable->name,
Classroom::class => 'Classe : '.$d->documentable->name,
$linked = $d->documentable;

return match (true) {
// Un élève n'a pas de colonne « name » : on compose nom + prénom.
$linked instanceof Student => 'Élève : '.trim($linked->firstname.' '.$linked->lastname),
$linked instanceof Classroom => 'Classe : '.$linked->name,
default => null,
};
}
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/CalendarEventController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function index(Request $request): Response
'title' => $e->title,
'description' => $e->description,
'type' => $e->type,
'start_date' => $e->start_date?->format('Y-m-d'),
'start_date' => $e->start_date->format('Y-m-d'),
'end_date' => $e->end_date?->format('Y-m-d'),
'all_day' => $e->all_day,
'start_time' => $e->start_time,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class CashAccountController extends Controller
public function index(): Response
{
$accounts = CashAccount::withCount('payments')
->withSum('transactions as total_income', 'amount', fn ($q) => $q->where('type', 'INCOME'))
->withSum(['transactions as total_income' => fn ($q) => $q->where('type', 'INCOME')], 'amount')
->orderBy('type')
->orderBy('name')
->get();
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Comptabilite/InvoiceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public function verifyReceipt(Request $request): Response
'valid' => true,
'receipt_number' => $receipt->receipt_number,
'amount' => (float) $receipt->payment->amount,
'paid_at' => $receipt->payment->paid_at?->format('d/m/Y'),
'paid_at' => $receipt->payment->paid_at->format('d/m/Y'),
'student' => $receipt->payment->invoice?->enrollment?->student
? $receipt->payment->invoice->enrollment->student->lastname.' '.$receipt->payment->invoice->enrollment->student->firstname
: null,
Expand Down
24 changes: 12 additions & 12 deletions app/Http/Controllers/Comptabilite/SituationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ classes.code AS cl
'lastname' => $e->student?->lastname,
'matricule' => $e->student?->matricule,
'invoice_number' => $e->invoice?->invoice_number,
'total' => (float) ($e->invoice?->total ?? 0),
'amount_paid' => (float) ($e->invoice?->amount_paid ?? 0),
'amount_remaining' => (float) ($e->invoice?->amount_remaining ?? 0),
'status' => $e->invoice?->status ?? 'ISSUED',
'total' => (float) ($e->invoice->total ?? 0),
'amount_paid' => (float) ($e->invoice->amount_paid ?? 0),
'amount_remaining' => (float) ($e->invoice->amount_remaining ?? 0),
'status' => $e->invoice->status ?? 'ISSUED',
]);
}

Expand Down Expand Up @@ -153,14 +153,14 @@ public function export(Request $request)
foreach ($enrollments as $e) {
$inv = $e->invoice;
fputcsv($out, [
$e->student?->matricule ?? '—',
$e->student?->lastname ?? '—',
$e->student?->firstname ?? '—',
$e->classroom?->name ?? '—',
$inv?->invoice_number ?? '—',
number_format((float) ($inv?->total ?? 0), 0, ',', ' '),
number_format((float) ($inv?->amount_paid ?? 0), 0, ',', ' '),
number_format((float) ($inv?->amount_remaining ?? 0), 0, ',', ' '),
$e->student->matricule ?? '—',
$e->student->lastname ?? '—',
$e->student->firstname ?? '—',
$e->classroom->name ?? '—',
$inv->invoice_number ?? '—',
number_format((float) ($inv->total ?? 0), 0, ',', ' '),
number_format((float) ($inv->amount_paid ?? 0), 0, ',', ' '),
number_format((float) ($inv->amount_remaining ?? 0), 0, ',', ' '),
$this->statusLabel($inv?->status),
], ';');
}
Expand Down
Loading
Loading