diff --git a/thanasoft-back/app/Http/Controllers/Api/ClientController.php b/thanasoft-back/app/Http/Controllers/Api/ClientController.php index 8b53f2c..ffd7ba2 100644 --- a/thanasoft-back/app/Http/Controllers/Api/ClientController.php +++ b/thanasoft-back/app/Http/Controllers/Api/ClientController.php @@ -228,6 +228,28 @@ class ClientController extends Controller ], 500); } } + /** + * Get aggregated client statistics. + */ + public function statistics(): JsonResponse + { + try { + $stats = $this->clientRepository->getStatistics(); + + return response()->json(['data' => $stats], 200); + } catch (\Exception $e) { + Log::error('Error fetching client statistics: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la récupération des statistiques.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } + /** * Change client status (active/inactive). */ diff --git a/thanasoft-back/app/Http/Controllers/Api/FinancialStatisticsController.php b/thanasoft-back/app/Http/Controllers/Api/FinancialStatisticsController.php new file mode 100644 index 0000000..1e91d2f --- /dev/null +++ b/thanasoft-back/app/Http/Controllers/Api/FinancialStatisticsController.php @@ -0,0 +1,47 @@ +repository->getStatistics(); + + return response()->json(['data' => $stats], 200); + } catch (\Exception $e) { + Log::error('Error fetching financial statistics: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la récupération des statistiques financières.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } +} diff --git a/thanasoft-back/app/Http/Controllers/Api/LeaveController.php b/thanasoft-back/app/Http/Controllers/Api/LeaveController.php new file mode 100644 index 0000000..715e24c --- /dev/null +++ b/thanasoft-back/app/Http/Controllers/Api/LeaveController.php @@ -0,0 +1,174 @@ +get('per_page', 15); + + $filters = [ + 'employee_id' => $request->get('employee_id'), + 'type' => $request->get('type'), + 'status' => $request->get('status'), + 'start_date' => $request->get('start_date'), + 'end_date' => $request->get('end_date'), + 'search' => $request->get('search'), + 'sort_by' => $request->get('sort_by', 'start_date'), + 'sort_direction' => $request->get('sort_direction', 'desc'), + ]; + + $filters = array_filter($filters, function ($value) { + return $value !== null && $value !== ''; + }); + + $result = $this->leaveRepository->getPaginated($perPage, $filters); + + return response()->json([ + 'data' => new LeaveCollection($result['leaves']), + 'pagination' => $result['pagination'], + 'message' => 'Congés récupérés avec succès.', + ], 200); + } catch (\Exception $e) { + Log::error('Error fetching leaves: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la récupération des congés.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } + + public function store(StoreLeaveRequest $request): LeaveResource|JsonResponse + { + try { + $payload = $request->validated(); + $payload['status'] = $payload['status'] ?? 'pending'; + + $leave = $this->leaveRepository->create($payload); + + return new LeaveResource($leave); + } catch (\Exception $e) { + Log::error('Error creating leave: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + 'data' => $request->validated(), + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la création du congé.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } + + public function show(string $id): LeaveResource|JsonResponse + { + try { + $leave = $this->leaveRepository->find($id); + + if (!$leave) { + return response()->json([ + 'message' => 'Congé non trouvé.', + ], 404); + } + + return new LeaveResource($leave); + } catch (\Exception $e) { + Log::error('Error fetching leave: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + 'leave_id' => $id, + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la récupération du congé.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } + + public function update(UpdateLeaveRequest $request, string $id): JsonResponse + { + try { + $updated = $this->leaveRepository->update($id, $request->validated()); + + if (!$updated) { + return response()->json([ + 'message' => 'Congé non trouvé ou échec de la mise à jour.', + ], 404); + } + + $leave = $this->leaveRepository->find($id); + + return response()->json([ + 'data' => new LeaveResource($leave), + 'message' => 'Congé mis à jour avec succès.', + 'status' => 'success', + ]); + } catch (\Exception $e) { + Log::error('Error updating leave: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + 'leave_id' => $id, + 'data' => $request->validated(), + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la mise à jour du congé.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } + + public function destroy(string $id): JsonResponse + { + try { + $deleted = $this->leaveRepository->delete($id); + + if (!$deleted) { + return response()->json([ + 'message' => 'Congé non trouvé ou échec de la suppression.', + ], 404); + } + + return response()->json([ + 'message' => 'Congé supprimé avec succès.', + 'status' => 'success', + ]); + } catch (\Exception $e) { + Log::error('Error deleting leave: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + 'leave_id' => $id, + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de la suppression du congé.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Http/Requests/StoreLeaveRequest.php b/thanasoft-back/app/Http/Requests/StoreLeaveRequest.php new file mode 100644 index 0000000..e37dabb --- /dev/null +++ b/thanasoft-back/app/Http/Requests/StoreLeaveRequest.php @@ -0,0 +1,49 @@ + 'required|exists:employees,id', + 'type' => ['required', Rule::in(['conge', 'repos', 'feriee'])], + 'status' => ['nullable', Rule::in(['pending', 'approved', 'rejected', 'cancelled'])], + 'start_date' => 'required|date', + 'end_date' => 'required|date|after_or_equal:start_date', + 'reason' => 'nullable|string', + 'notes' => 'nullable|string', + 'approved_by' => 'nullable|exists:users,id', + 'approved_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'employee_id.required' => 'L\'employé est obligatoire.', + 'employee_id.exists' => 'L\'employé sélectionné est invalide.', + 'type.required' => 'Le type de congé est obligatoire.', + 'type.in' => 'Le type de congé est invalide.', + 'status.in' => 'Le statut du congé est invalide.', + 'start_date.required' => 'La date de début est obligatoire.', + 'start_date.date' => 'La date de début doit être une date valide.', + 'end_date.required' => 'La date de fin est obligatoire.', + 'end_date.date' => 'La date de fin doit être une date valide.', + 'end_date.after_or_equal' => 'La date de fin doit être postérieure ou égale à la date de début.', + 'reason.string' => 'Le motif doit être une chaîne de caractères.', + 'notes.string' => 'Les notes doivent être une chaîne de caractères.', + 'approved_by.exists' => 'L\'approbateur sélectionné est invalide.', + 'approved_at.date' => 'La date d\'approbation doit être une date valide.', + ]; + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Http/Requests/UpdateLeaveRequest.php b/thanasoft-back/app/Http/Requests/UpdateLeaveRequest.php new file mode 100644 index 0000000..bd9d01c --- /dev/null +++ b/thanasoft-back/app/Http/Requests/UpdateLeaveRequest.php @@ -0,0 +1,45 @@ + 'nullable|exists:employees,id', + 'type' => ['nullable', Rule::in(['conge', 'repos', 'feriee'])], + 'status' => ['nullable', Rule::in(['pending', 'approved', 'rejected', 'cancelled'])], + 'start_date' => 'nullable|date', + 'end_date' => 'nullable|date|after_or_equal:start_date', + 'reason' => 'nullable|string', + 'notes' => 'nullable|string', + 'approved_by' => 'nullable|exists:users,id', + 'approved_at' => 'nullable|date', + ]; + } + + public function messages(): array + { + return [ + 'employee_id.exists' => 'L\'employé sélectionné est invalide.', + 'type.in' => 'Le type de congé est invalide.', + 'status.in' => 'Le statut du congé est invalide.', + 'start_date.date' => 'La date de début doit être une date valide.', + 'end_date.date' => 'La date de fin doit être une date valide.', + 'end_date.after_or_equal' => 'La date de fin doit être postérieure ou égale à la date de début.', + 'reason.string' => 'Le motif doit être une chaîne de caractères.', + 'notes.string' => 'Les notes doivent être une chaîne de caractères.', + 'approved_by.exists' => 'L\'approbateur sélectionné est invalide.', + 'approved_at.date' => 'La date d\'approbation doit être une date valide.', + ]; + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Http/Resources/Employee/LeaveCollection.php b/thanasoft-back/app/Http/Resources/Employee/LeaveCollection.php new file mode 100644 index 0000000..9081495 --- /dev/null +++ b/thanasoft-back/app/Http/Resources/Employee/LeaveCollection.php @@ -0,0 +1,43 @@ + $this->collection->map(function ($leave) { + return [ + 'id' => $leave->id, + 'employee_id' => $leave->employee_id, + 'type' => $leave->type, + 'status' => $leave->status, + 'start_date' => $leave->start_date?->format('Y-m-d'), + 'end_date' => $leave->end_date?->format('Y-m-d'), + 'reason' => $leave->reason, + 'notes' => $leave->notes, + 'approved_by' => $leave->approved_by, + 'approved_at' => $leave->approved_at?->format('Y-m-d H:i:s'), + 'created_at' => $leave->created_at?->format('Y-m-d H:i:s'), + 'updated_at' => $leave->updated_at?->format('Y-m-d H:i:s'), + 'employee' => $leave->employee ? [ + 'id' => $leave->employee->id, + 'first_name' => $leave->employee->first_name, + 'last_name' => $leave->employee->last_name, + 'full_name' => $leave->employee->full_name, + 'email' => $leave->employee->email, + 'job_title' => $leave->employee->job_title, + ] : null, + 'approver' => $leave->approver ? [ + 'id' => $leave->approver->id, + 'name' => $leave->approver->name, + 'email' => $leave->approver->email, + ] : null, + ]; + }), + ]; + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Http/Resources/Employee/LeaveHistoryResource.php b/thanasoft-back/app/Http/Resources/Employee/LeaveHistoryResource.php new file mode 100644 index 0000000..9b96cc2 --- /dev/null +++ b/thanasoft-back/app/Http/Resources/Employee/LeaveHistoryResource.php @@ -0,0 +1,29 @@ + $this->id, + 'leave_id' => $this->leave_id, + 'old_status' => $this->old_status, + 'new_status' => $this->new_status, + 'changed_at' => $this->changed_at?->format('Y-m-d H:i:s'), + 'comment' => $this->comment, + 'user' => $this->when( + $this->relationLoaded('user') && $this->user, + fn () => [ + 'id' => $this->user->id, + 'name' => $this->user->name, + 'email' => $this->user->email, + ] + ), + ]; + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Http/Resources/Employee/LeaveResource.php b/thanasoft-back/app/Http/Resources/Employee/LeaveResource.php new file mode 100644 index 0000000..9d061f9 --- /dev/null +++ b/thanasoft-back/app/Http/Resources/Employee/LeaveResource.php @@ -0,0 +1,50 @@ + $this->id, + 'employee_id' => $this->employee_id, + 'type' => $this->type, + 'status' => $this->status, + 'start_date' => $this->start_date?->format('Y-m-d'), + 'end_date' => $this->end_date?->format('Y-m-d'), + 'reason' => $this->reason, + 'notes' => $this->notes, + 'approved_by' => $this->approved_by, + 'approved_at' => $this->approved_at?->format('Y-m-d H:i:s'), + 'created_at' => $this->created_at?->format('Y-m-d H:i:s'), + 'updated_at' => $this->updated_at?->format('Y-m-d H:i:s'), + 'employee' => $this->when( + $this->relationLoaded('employee') && $this->employee, + fn () => [ + 'id' => $this->employee->id, + 'first_name' => $this->employee->first_name, + 'last_name' => $this->employee->last_name, + 'full_name' => $this->employee->full_name, + 'email' => $this->employee->email, + 'job_title' => $this->employee->job_title, + ] + ), + 'approver' => $this->when( + $this->relationLoaded('approver') && $this->approver, + fn () => [ + 'id' => $this->approver->id, + 'name' => $this->approver->name, + 'email' => $this->approver->email, + ] + ), + 'histories' => $this->when( + $this->relationLoaded('histories'), + fn () => LeaveHistoryResource::collection($this->histories) + ), + ]; + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Models/Employee.php b/thanasoft-back/app/Models/Employee.php index 5adb6f5..3bc07ac 100644 --- a/thanasoft-back/app/Models/Employee.php +++ b/thanasoft-back/app/Models/Employee.php @@ -58,6 +58,11 @@ class Employee extends Model return $this->hasMany(Vehicle::class, 'primary_user_id'); } + public function leaves(): HasMany + { + return $this->hasMany(Leave::class); + } + /** * Get the full name of the employee. */ diff --git a/thanasoft-back/app/Models/Leave.php b/thanasoft-back/app/Models/Leave.php new file mode 100644 index 0000000..f4dfee3 --- /dev/null +++ b/thanasoft-back/app/Models/Leave.php @@ -0,0 +1,58 @@ + + */ + protected $fillable = [ + 'employee_id', + 'type', + 'status', + 'start_date', + 'end_date', + 'reason', + 'notes', + 'approved_by', + 'approved_at', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'start_date' => 'date', + 'end_date' => 'date', + 'approved_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; + + public function employee(): BelongsTo + { + return $this->belongsTo(Employee::class); + } + + public function approver(): BelongsTo + { + return $this->belongsTo(User::class, 'approved_by'); + } + + public function histories(): HasMany + { + return $this->hasMany(LeaveHistory::class)->orderByDesc('changed_at'); + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Models/LeaveHistory.php b/thanasoft-back/app/Models/LeaveHistory.php new file mode 100644 index 0000000..665873b --- /dev/null +++ b/thanasoft-back/app/Models/LeaveHistory.php @@ -0,0 +1,49 @@ + + */ + protected $fillable = [ + 'leave_id', + 'old_status', + 'new_status', + 'changed_by', + 'changed_at', + 'comment', + ]; + + /** + * The attributes that should be cast. + * + * @var array + */ + protected $casts = [ + 'changed_at' => 'datetime', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; + + public function leave(): BelongsTo + { + return $this->belongsTo(Leave::class); + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class, 'changed_by'); + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Providers/AppServiceProvider.php b/thanasoft-back/app/Providers/AppServiceProvider.php index 53eb5c6..38d0e9c 100644 --- a/thanasoft-back/app/Providers/AppServiceProvider.php +++ b/thanasoft-back/app/Providers/AppServiceProvider.php @@ -61,6 +61,10 @@ class AppServiceProvider extends ServiceProvider return new \App\Repositories\EmployeeRepository($app->make(\App\Models\Employee::class)); }); + $this->app->bind(\App\Repositories\LeaveRepositoryInterface::class, function ($app) { + return new \App\Repositories\LeaveRepository($app->make(\App\Models\Leave::class)); + }); + $this->app->bind(\App\Repositories\ThanatopractitionerRepositoryInterface::class, function ($app) { return new \App\Repositories\ThanatopractitionerRepository($app->make(\App\Models\Thanatopractitioner::class)); }); diff --git a/thanasoft-back/app/Providers/RepositoryServiceProvider.php b/thanasoft-back/app/Providers/RepositoryServiceProvider.php index 129bc49..1f2ce6b 100644 --- a/thanasoft-back/app/Providers/RepositoryServiceProvider.php +++ b/thanasoft-back/app/Providers/RepositoryServiceProvider.php @@ -14,6 +14,8 @@ use App\Repositories\FileRepositoryInterface; use App\Repositories\FileRepository; use App\Repositories\WebmailMessageRepository; use App\Repositories\WebmailMessageRepositoryInterface; +use App\Repositories\FinancialStatisticsRepositoryInterface; +use App\Repositories\FinancialStatisticsRepository; use Illuminate\Support\ServiceProvider; class RepositoryServiceProvider extends ServiceProvider @@ -36,6 +38,7 @@ class RepositoryServiceProvider extends ServiceProvider $this->app->bind(\App\Repositories\ProductPackagingRepositoryInterface::class, \App\Repositories\ProductPackagingRepository::class); $this->app->bind(\App\Repositories\TvaRateRepositoryInterface::class, \App\Repositories\TvaRateRepository::class); $this->app->bind(\App\Repositories\GoodsReceiptRepositoryInterface::class, \App\Repositories\GoodsReceiptRepository::class); + $this->app->bind(FinancialStatisticsRepositoryInterface::class, FinancialStatisticsRepository::class); } /** diff --git a/thanasoft-back/app/Repositories/ClientRepository.php b/thanasoft-back/app/Repositories/ClientRepository.php index 309abb2..3ae0c56 100644 --- a/thanasoft-back/app/Repositories/ClientRepository.php +++ b/thanasoft-back/app/Repositories/ClientRepository.php @@ -7,6 +7,7 @@ namespace App\Repositories; use App\Models\Client; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Support\Facades\DB; use App\Repositories\ClientActivityTimelineRepositoryInterface; use Illuminate\Support\Facades\Log as LaravelLog; @@ -97,4 +98,105 @@ class ClientRepository extends BaseRepository implements ClientRepositoryInterfa return $query->get(); } + + /** + * Retrieve aggregated statistics about clients. + */ + public function getStatistics(): array + { + // 1. Clients actifs vs inactifs + $statusCounts = $this->model + ->selectRaw('is_active, COUNT(*) as total') + ->groupBy('is_active') + ->pluck('total', 'is_active'); + + $activeCount = (int) ($statusCounts[1] ?? 0); + $inactiveCount = (int) ($statusCounts[0] ?? 0); + $totalCount = $activeCount + $inactiveCount; + + // 2. Taux de rétention : clients ayant plus d'une intervention (dossier récurrent) + $clientsWithMultipleDossiers = DB::table('interventions') + ->select('client_id') + ->whereNotNull('client_id') + ->groupBy('client_id') + ->havingRaw('COUNT(*) > 1') + ->get() + ->count(); + + $retentionRate = $totalCount > 0 + ? round(($clientsWithMultipleDossiers / $totalCount) * 100, 2) + : 0.0; + + // 3. Délai moyen (jours) entre création du client et premier dossier (première intervention) + $avgDelayDays = DB::table('clients') + ->joinSub( + DB::table('interventions') + ->selectRaw('client_id, MIN(created_at) as first_intervention_at') + ->whereNotNull('client_id') + ->groupBy('client_id'), + 'first_interventions', + 'clients.id', + '=', + 'first_interventions.client_id' + ) + ->selectRaw('AVG(DATEDIFF(first_interventions.first_intervention_at, clients.created_at)) as avg_days') + ->value('avg_days'); + + // 4. Nombre de dossiers (interventions) par client — top 10 grands comptes + $dossiersPerClientTop10 = DB::table('interventions') + ->join('clients', 'interventions.client_id', '=', 'clients.id') + ->select( + 'clients.id', + 'clients.name', + DB::raw('COUNT(interventions.id) as total_dossiers') + ) + ->whereNotNull('interventions.client_id') + ->groupBy('clients.id', 'clients.name') + ->orderByDesc('total_dossiers') + ->limit(10) + ->get(); + + // 5. Répartition géographique des clients + $geographicDistribution = $this->model + ->selectRaw('billing_country_code, billing_city, COUNT(*) as total') + ->whereNotNull('billing_country_code') + ->groupBy('billing_country_code', 'billing_city') + ->orderByDesc('total') + ->get(); + + // 6. Groupes les plus représentés + $groupDistribution = DB::table('clients') + ->join('client_groups', 'clients.group_id', '=', 'client_groups.id') + ->select('client_groups.id', 'client_groups.name', DB::raw('COUNT(clients.id) as total')) + ->groupBy('client_groups.id', 'client_groups.name') + ->orderByDesc('total') + ->get(); + + // Catégories les plus représentées + $categoryDistribution = DB::table('clients') + ->join('client_categories', 'clients.client_category_id', '=', 'client_categories.id') + ->select('client_categories.id', 'client_categories.name', DB::raw('COUNT(clients.id) as total')) + ->groupBy('client_categories.id', 'client_categories.name') + ->orderByDesc('total') + ->get(); + + return [ + 'active_vs_inactive' => [ + 'active' => $activeCount, + 'inactive' => $inactiveCount, + 'total' => $totalCount, + ], + 'retention' => [ + 'clients_with_recurring_dossiers' => $clientsWithMultipleDossiers, + 'retention_rate_percentage' => $retentionRate, + ], + 'avg_delay_first_contact_to_first_dossier_days' => $avgDelayDays !== null + ? round((float) $avgDelayDays, 1) + : null, + 'dossiers_per_client_top10' => $dossiersPerClientTop10, + 'geographic_distribution' => $geographicDistribution, + 'group_distribution' => $groupDistribution, + 'category_distribution' => $categoryDistribution, + ]; + } } diff --git a/thanasoft-back/app/Repositories/ClientRepositoryInterface.php b/thanasoft-back/app/Repositories/ClientRepositoryInterface.php index 9de1baa..c981532 100644 --- a/thanasoft-back/app/Repositories/ClientRepositoryInterface.php +++ b/thanasoft-back/app/Repositories/ClientRepositoryInterface.php @@ -9,4 +9,6 @@ use Illuminate\Contracts\Pagination\LengthAwarePaginator; interface ClientRepositoryInterface extends BaseRepositoryInterface { public function paginate(int $perPage = 15, array $filters = []): LengthAwarePaginator; + + public function getStatistics(): array; } diff --git a/thanasoft-back/app/Repositories/FinancialStatisticsRepository.php b/thanasoft-back/app/Repositories/FinancialStatisticsRepository.php new file mode 100644 index 0000000..29e7e70 --- /dev/null +++ b/thanasoft-back/app/Repositories/FinancialStatisticsRepository.php @@ -0,0 +1,296 @@ + $this->revenueStats(), + 'quote_conversion' => $this->quoteConversionRate(), + 'avg_amount_per_case' => $this->avgAmountPerCase(), + 'avg_payment_delay' => $this->avgPaymentDelay(), + 'avoirs' => $this->avoirsStats(), + 'receivables' => $this->receivablesStats(), + ]; + } + + // ─── 1. Chiffre d'affaires mensuel & annuel ─────────────────────────────── + + private function revenueStats(): array + { + $currentYear = now()->year; + + // Monthly CA for current year + $monthly = DB::table('invoices') + ->selectRaw('MONTH(invoice_date) as month, SUM(total_ttc) as total_ttc, SUM(total_ht) as total_ht, COUNT(*) as count') + ->whereIn('status', self::REVENUE_STATUSES) + ->whereYear('invoice_date', $currentYear) + ->groupByRaw('MONTH(invoice_date)') + ->orderByRaw('MONTH(invoice_date)') + ->get() + ->keyBy('month'); + + // Build a full 12-month array (0 for missing months) + $monthlyFull = []; + for ($m = 1; $m <= 12; $m++) { + $row = $monthly->get($m); + $monthlyFull[] = [ + 'month' => $m, + 'total_ttc' => $row ? (float) $row->total_ttc : 0.0, + 'total_ht' => $row ? (float) $row->total_ht : 0.0, + 'count' => $row ? (int) $row->count : 0, + ]; + } + + // Annual CA — current and previous year for comparison + $annualRows = DB::table('invoices') + ->selectRaw('YEAR(invoice_date) as year, SUM(total_ttc) as total_ttc, SUM(total_ht) as total_ht, COUNT(*) as count') + ->whereIn('status', self::REVENUE_STATUSES) + ->whereYear('invoice_date', '>=', $currentYear - 1) + ->groupByRaw('YEAR(invoice_date)') + ->orderByRaw('YEAR(invoice_date)') + ->get() + ->keyBy('year'); + + $yearCurrent = $annualRows->get($currentYear); + $yearPrevious = $annualRows->get($currentYear - 1); + + $annualCurrentTtc = $yearCurrent ? (float) $yearCurrent->total_ttc : 0.0; + $annualPreviousTtc = $yearPrevious ? (float) $yearPrevious->total_ttc : 0.0; + + $annualGrowthPct = $annualPreviousTtc > 0 + ? round((($annualCurrentTtc - $annualPreviousTtc) / $annualPreviousTtc) * 100, 2) + : null; + + return [ + 'current_year' => $currentYear, + 'annual_current' => [ + 'total_ttc' => $annualCurrentTtc, + 'total_ht' => $yearCurrent ? (float) $yearCurrent->total_ht : 0.0, + 'count' => $yearCurrent ? (int) $yearCurrent->count : 0, + ], + 'annual_previous' => [ + 'total_ttc' => $annualPreviousTtc, + 'total_ht' => $yearPrevious ? (float) $yearPrevious->total_ht : 0.0, + 'count' => $yearPrevious ? (int) $yearPrevious->count : 0, + ], + 'annual_growth_pct' => $annualGrowthPct, + 'monthly' => $monthlyFull, + ]; + } + + // ─── 2. Taux de conversion devis → facture ──────────────────────────────── + + private function quoteConversionRate(): array + { + $totalQuotes = (int) DB::table('quotes') + ->whereNotIn('status', ['annule']) + ->count(); + + // A quote is "converted" when at least one invoice references it + $convertedQuotes = (int) DB::table('quotes') + ->join('invoices', 'invoices.source_quote_id', '=', 'quotes.id') + ->whereNotIn('quotes.status', ['annule']) + ->distinct('quotes.id') + ->count('quotes.id'); + + $rate = $totalQuotes > 0 + ? round(($convertedQuotes / $totalQuotes) * 100, 2) + : 0.0; + + // Breakdown by quote status + $byStatus = DB::table('quotes') + ->selectRaw('status, COUNT(*) as total') + ->groupBy('status') + ->get(); + + return [ + 'total_quotes' => $totalQuotes, + 'converted_quotes' => $convertedQuotes, + 'conversion_rate' => $rate, + 'by_status' => $byStatus, + ]; + } + + // ─── 3. Montant moyen par dossier (panier moyen) ───────────────────────── + + private function avgAmountPerCase(): array + { + $row = DB::table('invoices') + ->selectRaw('AVG(total_ttc) as avg_ttc, AVG(total_ht) as avg_ht, COUNT(*) as total_count, SUM(total_ttc) as sum_ttc') + ->whereIn('status', self::REVENUE_STATUSES) + ->first(); + + return [ + 'avg_ttc' => $row && $row->avg_ttc !== null ? round((float) $row->avg_ttc, 2) : null, + 'avg_ht' => $row && $row->avg_ht !== null ? round((float) $row->avg_ht, 2) : null, + 'total_count' => $row ? (int) $row->total_count : 0, + 'total_ttc' => $row ? (float) $row->sum_ttc : 0.0, + ]; + } + + // ─── 4. Délai moyen de paiement ─────────────────────────────────────────── + + private function avgPaymentDelay(): array + { + // Use document_status_history to find the exact moment status became 'payee' + $avgFromHistory = DB::table('invoices') + ->join('document_status_history as dsh', function ($join) { + $join->on('dsh.document_id', '=', 'invoices.id') + ->where('dsh.document_type', '=', 'invoice') + ->where('dsh.new_status', '=', 'payee'); + }) + ->selectRaw('AVG(DATEDIFF(dsh.changed_at, invoices.invoice_date)) as avg_days') + ->where('invoices.status', 'payee') + ->value('avg_days'); + + // Fallback: avg delay between invoice_date and due_date for paid invoices + $avgFromDueDate = DB::table('invoices') + ->selectRaw('AVG(DATEDIFF(due_date, invoice_date)) as avg_days') + ->where('status', 'payee') + ->whereNotNull('due_date') + ->value('avg_days'); + + // Count overdue invoices (echue = past due_date, still unpaid) + $overdueCount = (int) DB::table('invoices') + ->where('status', 'echue') + ->count(); + + $overdueTotal = (float) DB::table('invoices') + ->where('status', 'echue') + ->sum('total_ttc'); + + return [ + 'avg_days_to_payment' => $avgFromHistory !== null + ? round((float) $avgFromHistory, 1) + : ($avgFromDueDate !== null ? round((float) $avgFromDueDate, 1) : null), + 'avg_days_invoice_to_due' => $avgFromDueDate !== null + ? round((float) $avgFromDueDate, 1) + : null, + 'overdue_invoices_count' => $overdueCount, + 'overdue_invoices_total_ttc' => $overdueTotal, + ]; + } + + // ─── 5. Volume d'avoirs émis ────────────────────────────────────────────── + + private function avoirsStats(): array + { + $totals = DB::table('avoirs') + ->selectRaw('COUNT(*) as count, SUM(total_ttc) as total_ttc, SUM(total_ht) as total_ht') + ->whereIn('status', self::AVOIR_EMITTED_STATUSES) + ->first(); + + // Breakdown by reason type + $byReason = DB::table('avoirs') + ->selectRaw('reason_type, COUNT(*) as count, SUM(total_ttc) as total_ttc') + ->whereIn('status', self::AVOIR_EMITTED_STATUSES) + ->groupBy('reason_type') + ->orderByDesc('count') + ->get(); + + // Monthly trend (current year) + $monthlyTrend = DB::table('avoirs') + ->selectRaw('MONTH(avoir_date) as month, COUNT(*) as count, SUM(total_ttc) as total_ttc') + ->whereIn('status', self::AVOIR_EMITTED_STATUSES) + ->whereYear('avoir_date', now()->year) + ->groupByRaw('MONTH(avoir_date)') + ->orderByRaw('MONTH(avoir_date)') + ->get(); + + return [ + 'total_count' => $totals ? (int) $totals->count : 0, + 'total_ttc' => $totals ? (float) $totals->total_ttc : 0.0, + 'total_ht' => $totals ? (float) $totals->total_ht : 0.0, + 'by_reason' => $byReason, + 'monthly_trend' => $monthlyTrend, + ]; + } + + // ─── 6. Créances en cours (relances prioritaires) ───────────────────────── + + private function receivablesStats(): array + { + // Global totals + $totals = DB::table('invoices') + ->selectRaw('COUNT(*) as count, SUM(total_ttc) as total_ttc') + ->whereIn('status', self::RECEIVABLE_STATUSES) + ->first(); + + // Breakdown by status + $byStatus = DB::table('invoices') + ->selectRaw('status, COUNT(*) as count, SUM(total_ttc) as total_ttc') + ->whereIn('status', self::RECEIVABLE_STATUSES) + ->groupBy('status') + ->get(); + + // Top 10 clients with highest outstanding balance + $topDebtors = DB::table('invoices') + ->join('clients', 'invoices.client_id', '=', 'clients.id') + ->select( + 'clients.id', + 'clients.name', + DB::raw('COUNT(invoices.id) as invoice_count'), + DB::raw('SUM(invoices.total_ttc) as total_outstanding') + ) + ->whereIn('invoices.status', self::RECEIVABLE_STATUSES) + ->groupBy('clients.id', 'clients.name') + ->orderByDesc('total_outstanding') + ->limit(10) + ->get(); + + // Overdue (echue) + near-due (due within 7 days) detail + $criticalInvoices = DB::table('invoices') + ->join('clients', 'invoices.client_id', '=', 'clients.id') + ->select( + 'invoices.id', + 'invoices.invoice_number', + 'invoices.status', + 'invoices.due_date', + 'invoices.total_ttc', + 'clients.name as client_name', + 'clients.id as client_id', + DB::raw('DATEDIFF(NOW(), invoices.due_date) as days_overdue') + ) + ->where(function ($q) { + $q->where('invoices.status', 'echue') + ->orWhere(function ($q2) { + $q2->whereIn('invoices.status', ['emise', 'envoyee', 'partiellement_payee']) + ->whereRaw('invoices.due_date <= DATE_ADD(NOW(), INTERVAL 7 DAY)') + ->whereNotNull('invoices.due_date'); + }); + }) + ->orderByRaw('invoices.due_date ASC') + ->limit(20) + ->get(); + + return [ + 'total_count' => $totals ? (int) $totals->count : 0, + 'total_outstanding' => $totals ? (float) $totals->total_ttc : 0.0, + 'by_status' => $byStatus, + 'top_debtors' => $topDebtors, + 'critical_invoices' => $criticalInvoices, + ]; + } +} diff --git a/thanasoft-back/app/Repositories/FinancialStatisticsRepositoryInterface.php b/thanasoft-back/app/Repositories/FinancialStatisticsRepositoryInterface.php new file mode 100644 index 0000000..1a873e2 --- /dev/null +++ b/thanasoft-back/app/Repositories/FinancialStatisticsRepositoryInterface.php @@ -0,0 +1,10 @@ +model->newQuery() + ->with(['employee', 'approver', 'histories.user']) + ->orderByDesc('start_date') + ->get($columns); + } + + public function find(int|string $id, array $columns = ['*']): ?Model + { + return $this->model->newQuery() + ->with(['employee', 'approver', 'histories.user']) + ->find($id, $columns); + } + + public function create(array $attributes): Model + { + try { + DB::beginTransaction(); + + /** @var Leave $leave */ + $leave = $this->model->newQuery()->create($attributes); + + $this->recordHistory( + $leave, + null, + $leave->status, + $attributes['approved_by'] ?? null, + $attributes['notes'] ?? null + ); + + DB::commit(); + + return $leave->load(['employee', 'approver', 'histories.user']); + } catch (Exception $e) { + DB::rollBack(); + Log::error('Error creating leave: ' . $e->getMessage(), [ + 'attributes' => $attributes, + 'exception' => $e, + ]); + throw $e; + } + } + + public function update(int|string $id, array $attributes): bool + { + try { + DB::beginTransaction(); + + /** @var Leave|null $leave */ + $leave = $this->model->newQuery()->find($id); + if (!$leave) { + DB::rollBack(); + return false; + } + + $oldStatus = $leave->status; + $result = $leave->fill($attributes)->save(); + + if (array_key_exists('status', $attributes) && $attributes['status'] !== $oldStatus) { + $this->recordHistory( + $leave, + $oldStatus, + $leave->status, + $attributes['approved_by'] ?? $leave->approved_by, + $attributes['notes'] ?? null + ); + } + + DB::commit(); + + return $result; + } catch (Exception $e) { + DB::rollBack(); + Log::error('Error updating leave with ID ' . $id . ': ' . $e->getMessage(), [ + 'id' => $id, + 'attributes' => $attributes, + 'exception' => $e, + ]); + throw $e; + } + } + + public function getPaginated(int $perPage = 10, array $filters = []): array + { + $query = $this->model->newQuery()->with(['employee', 'approver', 'histories.user']); + + if (!empty($filters['employee_id'])) { + $query->where('employee_id', (int) $filters['employee_id']); + } + + if (!empty($filters['type'])) { + $query->where('type', $filters['type']); + } + + if (!empty($filters['status'])) { + $query->where('status', $filters['status']); + } + + if (!empty($filters['start_date'])) { + $query->whereDate('start_date', '>=', $filters['start_date']); + } + + if (!empty($filters['end_date'])) { + $query->whereDate('end_date', '<=', $filters['end_date']); + } + + if (!empty($filters['search'])) { + $search = (string) $filters['search']; + $query->where(function ($subQuery) use ($search) { + $subQuery->where('reason', 'like', '%' . $search . '%') + ->orWhere('notes', 'like', '%' . $search . '%') + ->orWhereHas('employee', function ($employeeQuery) use ($search) { + $employeeQuery->where('first_name', 'like', '%' . $search . '%') + ->orWhere('last_name', 'like', '%' . $search . '%') + ->orWhere('email', 'like', '%' . $search . '%'); + }); + }); + } + + $sortField = $filters['sort_by'] ?? 'start_date'; + $sortDirection = $filters['sort_direction'] ?? 'desc'; + + $allowedSortFields = ['start_date', 'end_date', 'status', 'type', 'created_at']; + if (!in_array($sortField, $allowedSortFields, true)) { + $sortField = 'start_date'; + } + + $sortDirection = strtolower((string) $sortDirection) === 'asc' ? 'asc' : 'desc'; + + $paginator = $query + ->orderBy($sortField, $sortDirection) + ->paginate($perPage); + + return [ + 'leaves' => $paginator->getCollection(), + 'pagination' => [ + 'current_page' => $paginator->currentPage(), + 'last_page' => $paginator->lastPage(), + 'per_page' => $paginator->perPage(), + 'total' => $paginator->total(), + 'from' => $paginator->firstItem(), + 'to' => $paginator->lastItem(), + ], + ]; + } + + private function recordHistory( + Leave $leave, + ?string $oldStatus, + string $newStatus, + int|string|null $changedBy = null, + ?string $comment = null + ): void { + LeaveHistory::query()->create([ + 'leave_id' => $leave->id, + 'old_status' => $oldStatus, + 'new_status' => $newStatus, + 'changed_by' => $changedBy, + 'changed_at' => now(), + 'comment' => $comment, + ]); + } +} \ No newline at end of file diff --git a/thanasoft-back/app/Repositories/LeaveRepositoryInterface.php b/thanasoft-back/app/Repositories/LeaveRepositoryInterface.php new file mode 100644 index 0000000..6651807 --- /dev/null +++ b/thanasoft-back/app/Repositories/LeaveRepositoryInterface.php @@ -0,0 +1,17 @@ + $filters + * @return array{leaves: \Illuminate\Support\Collection, pagination: array} + */ + public function getPaginated(int $perPage = 10, array $filters = []): array; +} \ No newline at end of file diff --git a/thanasoft-back/composer.lock b/thanasoft-back/composer.lock index 9f8af1e..77e3457 100644 --- a/thanasoft-back/composer.lock +++ b/thanasoft-back/composer.lock @@ -8,26 +8,26 @@ "packages": [ { "name": "barryvdh/laravel-dompdf", - "version": "v3.1.1", + "version": "v3.1.2", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-dompdf.git", - "reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d" + "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d", - "reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d", + "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/ee3b72b19ccdf57d0243116ecb2b90261344dedc", + "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc", "shasum": "" }, "require": { "dompdf/dompdf": "^3.0", - "illuminate/support": "^9|^10|^11|^12", + "illuminate/support": "^9|^10|^11|^12|^13.0", "php": "^8.1" }, "require-dev": { "larastan/larastan": "^2.7|^3.0", - "orchestra/testbench": "^7|^8|^9|^10", + "orchestra/testbench": "^7|^8|^9.16|^10|^11.0", "phpro/grumphp": "^2.5", "squizlabs/php_codesniffer": "^3.5" }, @@ -69,7 +69,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-dompdf/issues", - "source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.1" + "source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.2" }, "funding": [ { @@ -81,20 +81,20 @@ "type": "github" } ], - "time": "2025-02-13T15:07:54+00:00" + "time": "2026-02-21T08:51:10+00:00" }, { "name": "brick/math", - "version": "0.14.0", + "version": "0.14.8", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2" + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", - "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", "shasum": "" }, "require": { @@ -133,7 +133,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.0" + "source": "https://github.com/brick/math/tree/0.14.8" }, "funding": [ { @@ -141,7 +141,7 @@ "type": "github" } ], - "time": "2025-08-29T12:40:03+00:00" + "time": "2026-02-10T14:33:43+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -456,16 +456,16 @@ }, { "name": "dompdf/dompdf", - "version": "v3.1.4", + "version": "v3.1.5", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "db712c90c5b9868df3600e64e68da62e78a34623" + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/db712c90c5b9868df3600e64e68da62e78a34623", - "reference": "db712c90c5b9868df3600e64e68da62e78a34623", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", "shasum": "" }, "require": { @@ -514,22 +514,22 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v3.1.4" + "source": "https://github.com/dompdf/dompdf/tree/v3.1.5" }, - "time": "2025-10-29T12:43:30+00:00" + "time": "2026-03-03T13:54:37+00:00" }, { "name": "dompdf/php-font-lib", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d" + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", - "reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a", + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a", "shasum": "" }, "require": { @@ -537,7 +537,7 @@ "php": "^7.1 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12" }, "type": "library", "autoload": { @@ -559,9 +559,9 @@ "homepage": "https://github.com/dompdf/php-font-lib", "support": { "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/1.0.1" + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.2" }, - "time": "2024-12-02T14:37:59+00:00" + "time": "2026-01-20T14:10:26+00:00" }, { "name": "dompdf/php-svg-lib", @@ -611,29 +611,28 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.4.0", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "8c784d071debd117328803d86b2097615b457500" + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", - "reference": "8c784d071debd117328803d86b2097615b457500", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013", "shasum": "" }, "require": { - "php": "^7.2|^8.0", - "webmozart/assert": "^1.0" + "php": "^8.2|^8.3|^8.4|^8.5" }, "replace": { "mtdowling/cron-expression": "^1.0" }, "require-dev": { - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.0", - "phpunit/phpunit": "^7.0|^8.0|^9.0" + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.32|^2.1.31", + "phpunit/phpunit": "^8.5.48|^9.0" }, "type": "library", "extra": { @@ -664,7 +663,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.6.0" }, "funding": [ { @@ -672,7 +671,7 @@ "type": "github" } ], - "time": "2024-10-09T13:47:03+00:00" + "time": "2025-10-31T18:51:33+00:00" }, { "name": "egulias/email-validator", @@ -743,31 +742,31 @@ }, { "name": "fruitcake/php-cors", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/fruitcake/php-cors.git", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", - "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", "shasum": "" }, "require": { - "php": "^7.4|^8.0", - "symfony/http-foundation": "^4.4|^5.4|^6|^7" + "php": "^8.1", + "symfony/http-foundation": "^5.4|^6.4|^7.3|^8" }, "require-dev": { - "phpstan/phpstan": "^1.4", + "phpstan/phpstan": "^2", "phpunit/phpunit": "^9", - "squizlabs/php_codesniffer": "^3.5" + "squizlabs/php_codesniffer": "^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -798,7 +797,7 @@ ], "support": { "issues": "https://github.com/fruitcake/php-cors/issues", - "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0" }, "funding": [ { @@ -810,28 +809,28 @@ "type": "github" } ], - "time": "2023-10-12T05:21:21+00:00" + "time": "2025-12-03T09:33:47+00:00" }, { "name": "graham-campbell/result-type", - "version": "v1.1.3", + "version": "v1.1.4", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", - "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3" + "phpoption/phpoption": "^1.9.5" }, "require-dev": { - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" }, "type": "library", "autoload": { @@ -860,7 +859,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" }, "funding": [ { @@ -872,7 +871,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:45:45+00:00" + "time": "2025-12-27T19:43:20+00:00" }, { "name": "guzzlehttp/guzzle", @@ -1085,16 +1084,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.8.0", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "21dc724a0583619cd1652f673303492272778051" + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", - "reference": "21dc724a0583619cd1652f673303492272778051", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", "shasum": "" }, "require": { @@ -1110,6 +1109,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", + "jshttp/mime-db": "1.54.0.1", "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { @@ -1181,7 +1181,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.8.0" + "source": "https://github.com/guzzle/psr7/tree/2.9.0" }, "funding": [ { @@ -1197,7 +1197,7 @@ "type": "tidelift" } ], - "time": "2025-08-23T21:21:41+00:00" + "time": "2026-03-10T16:41:02+00:00" }, { "name": "guzzlehttp/uri-template", @@ -1287,16 +1287,16 @@ }, { "name": "laravel/framework", - "version": "v12.31.1", + "version": "v12.58.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "281b711710c245dd8275d73132e92635be3094df" + "reference": "6172ae1f44ba5d89e111057ee4a4e7c27f5a610d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/281b711710c245dd8275d73132e92635be3094df", - "reference": "281b711710c245dd8275d73132e92635be3094df", + "url": "https://api.github.com/repos/laravel/framework/zipball/6172ae1f44ba5d89e111057ee4a4e7c27f5a610d", + "reference": "6172ae1f44ba5d89e111057ee4a4e7c27f5a610d", "shasum": "" }, "require": { @@ -1317,14 +1317,13 @@ "guzzlehttp/uri-template": "^1.0", "laravel/prompts": "^0.3.0", "laravel/serializable-closure": "^1.3|^2.0", - "league/commonmark": "^2.7", + "league/commonmark": "^2.8.1", "league/flysystem": "^3.25.1", "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", "monolog/monolog": "^3.0", "nesbot/carbon": "^3.8.4", "nunomaduro/termwind": "^2.0", - "phiki/phiki": "^2.0.0", "php": "^8.2", "psr/container": "^1.1.1|^2.0.1", "psr/log": "^1.0|^2.0|^3.0", @@ -1338,8 +1337,8 @@ "symfony/mailer": "^7.2.0", "symfony/mime": "^7.2.0", "symfony/polyfill-php83": "^1.33", - "symfony/polyfill-php84": "^1.33", - "symfony/polyfill-php85": "^1.33", + "symfony/polyfill-php84": "^1.34", + "symfony/polyfill-php85": "^1.34", "symfony/process": "^7.2.0", "symfony/routing": "^7.2.0", "symfony/uid": "^7.2.0", @@ -1385,6 +1384,7 @@ "illuminate/process": "self.version", "illuminate/queue": "self.version", "illuminate/redis": "self.version", + "illuminate/reflection": "self.version", "illuminate/routing": "self.version", "illuminate/session": "self.version", "illuminate/support": "self.version", @@ -1409,13 +1409,13 @@ "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", "opis/json-schema": "^2.4.1", - "orchestra/testbench-core": "^10.6.5", + "orchestra/testbench-core": "^10.9.0", "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", - "phpstan/phpstan": "^2.0", + "phpstan/phpstan": "^2.1.41", "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", "predis/predis": "^2.3|^3.0", - "resend/resend-php": "^0.10.0", + "resend/resend-php": "^0.10.0|^1.0", "symfony/cache": "^7.2.0", "symfony/http-client": "^7.2.0", "symfony/psr-http-message-bridge": "^7.2.0", @@ -1449,7 +1449,7 @@ "predis/predis": "Required to use the predis connector (^2.3|^3.0).", "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", - "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", + "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0|^1.0).", "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", @@ -1471,6 +1471,7 @@ "src/Illuminate/Filesystem/functions.php", "src/Illuminate/Foundation/helpers.php", "src/Illuminate/Log/functions.php", + "src/Illuminate/Reflection/helpers.php", "src/Illuminate/Support/functions.php", "src/Illuminate/Support/helpers.php" ], @@ -1479,7 +1480,8 @@ "Illuminate\\Support\\": [ "src/Illuminate/Macroable/", "src/Illuminate/Collections/", - "src/Illuminate/Conditionable/" + "src/Illuminate/Conditionable/", + "src/Illuminate/Reflection/" ] } }, @@ -1503,36 +1505,36 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-09-23T15:33:04+00:00" + "time": "2026-04-26T16:42:04+00:00" }, { "name": "laravel/prompts", - "version": "v0.3.7", + "version": "v0.3.17", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc" + "reference": "6a82ac19a28b916ae0885828795dbd4c59d9a818" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/a1891d362714bc40c8d23b0b1d7090f022ea27cc", - "reference": "a1891d362714bc40c8d23b0b1d7090f022ea27cc", + "url": "https://api.github.com/repos/laravel/prompts/zipball/6a82ac19a28b916ae0885828795dbd4c59d9a818", + "reference": "6a82ac19a28b916ae0885828795dbd4c59d9a818", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", "ext-mbstring": "*", "php": "^8.1", - "symfony/console": "^6.2|^7.0" + "symfony/console": "^6.2|^7.0|^8.0" }, "conflict": { "illuminate/console": ">=10.17.0 <10.25.0", "laravel/framework": ">=10.17.0 <10.25.0" }, "require-dev": { - "illuminate/collections": "^10.0|^11.0|^12.0", + "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", "mockery/mockery": "^1.5", - "pestphp/pest": "^2.3|^3.4", + "pestphp/pest": "^2.3|^3.4|^4.0", "phpstan/phpstan": "^1.12.28", "phpstan/phpstan-mockery": "^1.1.3" }, @@ -1560,38 +1562,37 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.7" + "source": "https://github.com/laravel/prompts/tree/v0.3.17" }, - "time": "2025-09-19T13:47:56+00:00" + "time": "2026-04-20T16:07:33+00:00" }, { "name": "laravel/sanctum", - "version": "v4.2.0", + "version": "v4.3.2", "source": { "type": "git", "url": "https://github.com/laravel/sanctum.git", - "reference": "fd6df4f79f48a72992e8d29a9c0ee25422a0d677" + "reference": "2a9bccc18e9907808e0018dd15fa643937886b1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sanctum/zipball/fd6df4f79f48a72992e8d29a9c0ee25422a0d677", - "reference": "fd6df4f79f48a72992e8d29a9c0ee25422a0d677", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/2a9bccc18e9907808e0018dd15fa643937886b1e", + "reference": "2a9bccc18e9907808e0018dd15fa643937886b1e", "shasum": "" }, "require": { "ext-json": "*", - "illuminate/console": "^11.0|^12.0", - "illuminate/contracts": "^11.0|^12.0", - "illuminate/database": "^11.0|^12.0", - "illuminate/support": "^11.0|^12.0", + "illuminate/console": "^11.0|^12.0|^13.0", + "illuminate/contracts": "^11.0|^12.0|^13.0", + "illuminate/database": "^11.0|^12.0|^13.0", + "illuminate/support": "^11.0|^12.0|^13.0", "php": "^8.2", - "symfony/console": "^7.0" + "symfony/console": "^7.0|^8.0" }, "require-dev": { "mockery/mockery": "^1.6", - "orchestra/testbench": "^9.0|^10.0", - "phpstan/phpstan": "^1.10", - "phpunit/phpunit": "^11.3" + "orchestra/testbench": "^9.15|^10.8|^11.0", + "phpstan/phpstan": "^1.10" }, "type": "library", "extra": { @@ -1626,31 +1627,31 @@ "issues": "https://github.com/laravel/sanctum/issues", "source": "https://github.com/laravel/sanctum" }, - "time": "2025-07-09T19:45:24+00:00" + "time": "2026-04-30T11:46:25+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.5", + "version": "v2.0.13", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "3832547db6e0e2f8bb03d4093857b378c66eceed" + "reference": "b566ee0dd251f3c4078bed003a7ce015f5ea6dce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3832547db6e0e2f8bb03d4093857b378c66eceed", - "reference": "3832547db6e0e2f8bb03d4093857b378c66eceed", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b566ee0dd251f3c4078bed003a7ce015f5ea6dce", + "reference": "b566ee0dd251f3c4078bed003a7ce015f5ea6dce", "shasum": "" }, "require": { "php": "^8.1" }, "require-dev": { - "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", "nesbot/carbon": "^2.67|^3.0", - "pestphp/pest": "^2.36|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", "phpstan/phpstan": "^2.0", - "symfony/var-dumper": "^6.2.0|^7.0.0" + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" }, "type": "library", "extra": { @@ -1687,20 +1688,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2025-09-22T17:29:40+00:00" + "time": "2026-04-16T14:03:50+00:00" }, { "name": "laravel/tinker", - "version": "v2.10.1", + "version": "v2.11.1", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", - "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", "shasum": "" }, "require": { @@ -1709,7 +1710,7 @@ "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", "php": "^7.2.5|^8.0", "psy/psysh": "^0.11.1|^0.12.0", - "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0|^8.0" }, "require-dev": { "mockery/mockery": "~1.3.3|^1.4.2", @@ -1751,22 +1752,22 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.10.1" + "source": "https://github.com/laravel/tinker/tree/v2.11.1" }, - "time": "2025-01-27T14:24:01+00:00" + "time": "2026-02-06T14:12:35+00:00" }, { "name": "league/commonmark", - "version": "2.7.1", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "10732241927d3971d28e7ea7b5712721fa2296ca" + "reference": "59fb075d2101740c337c7216e3f32b36c204218b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/10732241927d3971d28e7ea7b5712721fa2296ca", - "reference": "10732241927d3971d28e7ea7b5712721fa2296ca", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/59fb075d2101740c337c7216e3f32b36c204218b", + "reference": "59fb075d2101740c337c7216e3f32b36c204218b", "shasum": "" }, "require": { @@ -1791,9 +1792,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 | ^7.0", - "symfony/process": "^5.4 | ^6.0 | ^7.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" }, @@ -1803,7 +1804,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.8-dev" + "dev-main": "2.9-dev" } }, "autoload": { @@ -1860,7 +1861,7 @@ "type": "tidelift" } ], - "time": "2025-07-20T12:47:49+00:00" + "time": "2026-03-19T13:16:38+00:00" }, { "name": "league/config", @@ -1946,16 +1947,16 @@ }, { "name": "league/flysystem", - "version": "3.30.0", + "version": "3.33.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "2203e3151755d874bb2943649dae1eb8533ac93e" + "reference": "570b8871e0ce693764434b29154c54b434905350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e", - "reference": "2203e3151755d874bb2943649dae1eb8533ac93e", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/570b8871e0ce693764434b29154c54b434905350", + "reference": "570b8871e0ce693764434b29154c54b434905350", "shasum": "" }, "require": { @@ -2023,22 +2024,22 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.30.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.33.0" }, - "time": "2025-06-25T13:29:59+00:00" + "time": "2026-03-25T07:59:30+00:00" }, { "name": "league/flysystem-local", - "version": "3.30.0", + "version": "3.31.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10" + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/6691915f77c7fb69adfb87dcd550052dc184ee10", - "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079", "shasum": "" }, "require": { @@ -2072,9 +2073,9 @@ "local" ], "support": { - "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.0" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.31.0" }, - "time": "2025-05-21T10:34:19+00:00" + "time": "2026-01-23T15:30:45+00:00" }, { "name": "league/mime-type-detection", @@ -2134,33 +2135,38 @@ }, { "name": "league/uri", - "version": "7.5.1", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/08cf38e3924d4f56238125547b5720496fac8fd4", + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" + "league/uri-interfaces": "^7.8.1", + "php": "^8.1", + "psr/http-factory": "^1" }, "conflict": { "league/uri-schemes": "^1.0" }, "suggest": { "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", "ext-fileinfo": "to create Data URI from file contennts", "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -2188,6 +2194,7 @@ "description": "URI manipulation library", "homepage": "https://uri.thephpleague.com", "keywords": [ + "URN", "data-uri", "file-uri", "ftp", @@ -2200,9 +2207,11 @@ "psr-7", "query-string", "querystring", + "rfc2141", "rfc3986", "rfc3987", "rfc6570", + "rfc8141", "uri", "uri-template", "url", @@ -2212,7 +2221,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" + "source": "https://github.com/thephpleague/uri/tree/7.8.1" }, "funding": [ { @@ -2220,26 +2229,25 @@ "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2026-03-15T20:22:25+00:00" }, { "name": "league/uri-interfaces", - "version": "7.5.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/85d5c77c5d6d3af6c54db4a78246364908f3c928", + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928", "shasum": "" }, "require": { "ext-filter": "*", "php": "^8.1", - "psr/http-factory": "^1", "psr/http-message": "^1.1 || ^2.0" }, "suggest": { @@ -2247,6 +2255,7 @@ "ext-gmp": "to improve IPV4 host parsing", "ext-intl": "to handle IDN host with the best performance", "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" }, "type": "library", @@ -2271,7 +2280,7 @@ "homepage": "https://nyamsprod.com" } ], - "description": "Common interfaces and classes for URI representation and interaction", + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", "homepage": "https://uri.thephpleague.com", "keywords": [ "data-uri", @@ -2296,7 +2305,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.1" }, "funding": [ { @@ -2304,7 +2313,7 @@ "type": "github" } ], - "time": "2024-12-08T08:18:47+00:00" + "time": "2026-03-08T20:05:35+00:00" }, { "name": "masterminds/html5", @@ -2375,16 +2384,16 @@ }, { "name": "monolog/monolog", - "version": "3.9.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", "shasum": "" }, "require": { @@ -2402,7 +2411,7 @@ "graylog2/gelf-php": "^1.4.2 || ^2.0", "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", + "mongodb/mongodb": "^1.8 || ^2.0", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.8", "phpstan/phpstan": "^2", @@ -2462,7 +2471,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" }, "funding": [ { @@ -2474,20 +2483,20 @@ "type": "tidelift" } ], - "time": "2025-03-24T10:02:05+00:00" + "time": "2026-01-02T08:56:05+00:00" }, { "name": "nesbot/carbon", - "version": "3.10.3", + "version": "3.11.4", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f" + "reference": "e890471a3494740f7d9326d72ce6a8c559ffee60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", - "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/e890471a3494740f7d9326d72ce6a8c559ffee60", + "reference": "e890471a3494740f7d9326d72ce6a8c559ffee60", "shasum": "" }, "require": { @@ -2495,9 +2504,9 @@ "ext-json": "*", "php": "^8.1", "psr/clock": "^1.0", - "symfony/clock": "^6.3.12 || ^7.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", "symfony/polyfill-mbstring": "^1.0", - "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" }, "provide": { "psr/clock-implementation": "1.0" @@ -2511,7 +2520,7 @@ "phpstan/extension-installer": "^1.4.3", "phpstan/phpstan": "^2.1.22", "phpunit/phpunit": "^10.5.53", - "squizlabs/php_codesniffer": "^3.13.4" + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.0" }, "bin": [ "bin/carbon" @@ -2554,14 +2563,14 @@ } ], "description": "An API extension for DateTime that supports 281 different languages.", - "homepage": "https://carbon.nesbot.com", + "homepage": "https://carbonphp.github.io/carbon/", "keywords": [ "date", "datetime", "time" ], "support": { - "docs": "https://carbon.nesbot.com/docs", + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", "issues": "https://github.com/CarbonPHP/carbon/issues", "source": "https://github.com/CarbonPHP/carbon" }, @@ -2579,29 +2588,31 @@ "type": "tidelift" } ], - "time": "2025-09-06T13:39:36+00:00" + "time": "2026-04-07T09:57:54+00:00" }, { "name": "nette/schema", - "version": "v1.3.2", + "version": "v1.3.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", - "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", "shasum": "" }, "require": { "nette/utils": "^4.0", - "php": "8.1 - 8.4" + "php": "8.1 - 8.5" }, "require-dev": { - "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^1.0", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -2611,6 +2622,9 @@ } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -2639,26 +2653,26 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.2" + "source": "https://github.com/nette/schema/tree/v1.3.5" }, - "time": "2024-10-06T23:10:23+00:00" + "time": "2026-02-23T03:47:12+00:00" }, { "name": "nette/utils", - "version": "v4.0.8", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", "shasum": "" }, "require": { - "php": "8.0 - 8.5" + "php": "8.2 - 8.5" }, "conflict": { "nette/finder": "<3", @@ -2666,8 +2680,10 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", "nette/tester": "^2.5", - "phpstan/phpstan-nette": "^2.0@stable", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -2681,7 +2697,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "4.1-dev" } }, "autoload": { @@ -2728,22 +2744,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.8" + "source": "https://github.com/nette/utils/tree/v4.1.3" }, - "time": "2025-08-06T21:43:34+00:00" + "time": "2026-02-13T03:05:33+00:00" }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.7.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", "shasum": "" }, "require": { @@ -2786,37 +2802,37 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" }, - "time": "2025-08-13T20:13:15+00:00" + "time": "2025-12-06T11:56:16+00:00" }, { "name": "nunomaduro/termwind", - "version": "v2.3.1", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "dfa08f390e509967a15c22493dc0bac5733d9123" + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123", - "reference": "dfa08f390e509967a15c22493dc0bac5733d9123", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.2.6" + "symfony/console": "^7.4.4 || ^8.0.4" }, "require-dev": { - "illuminate/console": "^11.44.7", - "laravel/pint": "^1.22.0", + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.2", - "phpstan/phpstan": "^1.12.25", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", + "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.2.6", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -2848,7 +2864,7 @@ "email": "enunomaduro@gmail.com" } ], - "description": "Its like Tailwind CSS, but for the console.", + "description": "It's like Tailwind CSS, but for the console.", "keywords": [ "cli", "console", @@ -2859,7 +2875,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1" + "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" }, "funding": [ { @@ -2875,91 +2891,20 @@ "type": "github" } ], - "time": "2025-05-08T08:14:37+00:00" - }, - { - "name": "phiki/phiki", - "version": "v2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phikiphp/phiki.git", - "reference": "160785c50c01077780ab217e5808f00ab8f05a13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phikiphp/phiki/zipball/160785c50c01077780ab217e5808f00ab8f05a13", - "reference": "160785c50c01077780ab217e5808f00ab8f05a13", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "league/commonmark": "^2.5.3", - "php": "^8.2", - "psr/simple-cache": "^3.0" - }, - "require-dev": { - "illuminate/support": "^11.45", - "laravel/pint": "^1.18.1", - "orchestra/testbench": "^9.15", - "pestphp/pest": "^3.5.1", - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^2.0", - "symfony/var-dumper": "^7.1.6" - }, - "type": "library", - "extra": { - "laravel": { - "providers": [ - "Phiki\\Adapters\\Laravel\\PhikiServiceProvider" - ] - } - }, - "autoload": { - "psr-4": { - "Phiki\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ryan Chandler", - "email": "support@ryangjchandler.co.uk", - "homepage": "https://ryangjchandler.co.uk", - "role": "Developer" - } - ], - "description": "Syntax highlighting using TextMate grammars in PHP.", - "support": { - "issues": "https://github.com/phikiphp/phiki/issues", - "source": "https://github.com/phikiphp/phiki/tree/v2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sponsors/ryangjchandler", - "type": "github" - }, - { - "url": "https://buymeacoffee.com/ryangjchandler", - "type": "other" - } - ], - "time": "2025-09-20T17:21:02+00:00" + "time": "2026-02-16T23:10:27+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.4", + "version": "1.9.5", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", - "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", "shasum": "" }, "require": { @@ -3009,7 +2954,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" }, "funding": [ { @@ -3021,7 +2966,7 @@ "type": "tidelift" } ], - "time": "2025-08-21T11:53:16+00:00" + "time": "2025-12-27T19:41:33+00:00" }, { "name": "psr/clock", @@ -3437,16 +3382,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.12", + "version": "v0.12.22", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "cd23863404a40ccfaf733e3af4db2b459837f7e7" + "reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/cd23863404a40ccfaf733e3af4db2b459837f7e7", - "reference": "cd23863404a40ccfaf733e3af4db2b459837f7e7", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/3be75d5b9244936dd4ac62ade2bfb004d13acf0f", + "reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f", "shasum": "" }, "require": { @@ -3454,18 +3399,19 @@ "ext-tokenizer": "*", "nikic/php-parser": "^5.0 || ^4.0", "php": "^8.0 || ^7.4", - "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", - "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" }, "conflict": { "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.2" + "bamarni/composer-bin-plugin": "^1.2", + "composer/class-map-generator": "^1.6" }, "suggest": { + "composer/class-map-generator": "Improved tab completion performance with better class discovery.", "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", - "ext-pdo-sqlite": "The doc command requires SQLite to work.", "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." }, "bin": [ @@ -3509,9 +3455,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.12" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.22" }, - "time": "2025-09-20T13:46:31+00:00" + "time": "2026-03-22T23:03:24+00:00" }, { "name": "ralouphie/getallheaders", @@ -3635,20 +3581,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.1", + "version": "4.9.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440" + "reference": "8429c78ca35a09f27565311b98101e2826affde0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440", - "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -3707,39 +3653,41 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.1" + "source": "https://github.com/ramsey/uuid/tree/4.9.2" }, - "time": "2025-09-04T20:59:21+00:00" + "time": "2025-12-14T04:43:48+00:00" }, { "name": "sabberworm/php-css-parser", - "version": "v9.1.0", + "version": "v9.3.0", "source": { "type": "git", "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb" + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb", - "reference": "1b363fdbdc6dd0ca0f4bf98d3a4d7f388133f1fb", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", "shasum": "" }, "require": { "ext-iconv": "*", "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", - "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.3" + "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "1.4.0", "phpstan/extension-installer": "1.4.3", - "phpstan/phpstan": "1.12.28 || 2.1.25", - "phpstan/phpstan-phpunit": "1.4.2 || 2.0.7", - "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.6", - "phpunit/phpunit": "8.5.46", + "phpstan/phpstan": "1.12.32 || 2.1.32", + "phpstan/phpstan-phpunit": "1.4.2 || 2.0.8", + "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7", + "phpunit/phpunit": "8.5.52", "rawr/phpunit-data-provider": "3.3.1", - "rector/rector": "1.2.10 || 2.1.7", - "rector/type-perfect": "1.0.0 || 2.1.0" + "rector/rector": "1.2.10 || 2.2.8", + "rector/type-perfect": "1.0.0 || 2.1.0", + "squizlabs/php_codesniffer": "4.0.1", + "thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1" }, "suggest": { "ext-mbstring": "for parsing UTF-8 CSS" @@ -3747,10 +3695,14 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "9.2.x-dev" + "dev-main": "9.4.x-dev" } }, "autoload": { + "files": [ + "src/Rule/Rule.php", + "src/RuleSet/RuleContainer.php" + ], "psr-4": { "Sabberworm\\CSS\\": "src/" } @@ -3781,9 +3733,9 @@ ], "support": { "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.1.0" + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0" }, - "time": "2025-09-14T07:37:21+00:00" + "time": "2026-03-03T17:31:43+00:00" }, { "name": "spatie/laravel-permission", @@ -3871,16 +3823,16 @@ }, { "name": "symfony/clock", - "version": "v7.3.0", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", - "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "url": "https://api.github.com/repos/symfony/clock/zipball/674fa3b98e21531dd040e613479f5f6fa8f32111", + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111", "shasum": "" }, "require": { @@ -3925,7 +3877,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.3.0" + "source": "https://github.com/symfony/clock/tree/v7.4.8" }, "funding": [ { @@ -3936,25 +3888,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/console", - "version": "v7.3.3", + "version": "v7.4.9", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7" + "reference": "d7d2b64a45a89d607865927b176fa51c33ddbb58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", - "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", + "url": "https://api.github.com/repos/symfony/console/zipball/d7d2b64a45a89d607865927b176fa51c33ddbb58", + "reference": "d7d2b64a45a89d607865927b176fa51c33ddbb58", "shasum": "" }, "require": { @@ -3962,7 +3918,7 @@ "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2" + "symfony/string": "^7.2|^8.0" }, "conflict": { "symfony/dependency-injection": "<6.4", @@ -3976,16 +3932,16 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4019,7 +3975,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.3" + "source": "https://github.com/symfony/console/tree/v7.4.9" }, "funding": [ { @@ -4039,20 +3995,20 @@ "type": "tidelift" } ], - "time": "2025-08-25T06:35:40+00:00" + "time": "2026-04-22T15:21:55+00:00" }, { "name": "symfony/css-selector", - "version": "v7.3.0", + "version": "v7.4.9", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + "reference": "b75663ed96cf4756e28e3105476f220f92886cc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b75663ed96cf4756e28e3105476f220f92886cc4", + "reference": "b75663ed96cf4756e28e3105476f220f92886cc4", "shasum": "" }, "require": { @@ -4088,7 +4044,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.3.0" + "source": "https://github.com/symfony/css-selector/tree/v7.4.9" }, "funding": [ { @@ -4099,25 +4055,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-04-18T13:18:21+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", + "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", "shasum": "" }, "require": { @@ -4130,7 +4090,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -4155,7 +4115,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" }, "funding": [ { @@ -4166,41 +4126,46 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-04-13T15:52:40+00:00" }, { "name": "symfony/error-handler", - "version": "v7.3.2", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3" + "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/0b31a944fcd8759ae294da4d2808cbc53aebd0c3", - "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", + "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "conflict": { "symfony/deprecation-contracts": "<2.5", "symfony/http-kernel": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ @@ -4232,7 +4197,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.3.2" + "source": "https://github.com/symfony/error-handler/tree/v7.4.8" }, "funding": [ { @@ -4252,20 +4217,20 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:57+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.3.3", + "version": "v7.4.9", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" + "reference": "e4a2e29753c7801f7a8340e066cfa788f3bc8101" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", - "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e4a2e29753c7801f7a8340e066cfa788f3bc8101", + "reference": "e4a2e29753c7801f7a8340e066cfa788f3bc8101", "shasum": "" }, "require": { @@ -4282,13 +4247,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/error-handler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^6.4|^7.0" + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4316,7 +4282,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.9" }, "funding": [ { @@ -4336,20 +4302,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2026-04-18T13:18:21+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32", + "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32", "shasum": "" }, "require": { @@ -4363,7 +4329,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -4396,7 +4362,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0" }, "funding": [ { @@ -4407,32 +4373,36 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2026-01-05T13:30:16+00:00" }, { "name": "symfony/finder", - "version": "v7.3.2", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" + "reference": "e0be088d22278583a82da281886e8c3592fbf149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", + "url": "https://api.github.com/repos/symfony/finder/zipball/e0be088d22278583a82da281886e8c3592fbf149", + "reference": "e0be088d22278583a82da281886e8c3592fbf149", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4460,7 +4430,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.2" + "source": "https://github.com/symfony/finder/tree/v7.4.8" }, "funding": [ { @@ -4480,27 +4450,26 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.3.3", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00" + "reference": "9381209597ec66c25be154cbf2289076e64d1eab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00", - "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9381209597ec66c25be154cbf2289076e64d1eab", + "reference": "9381209597ec66c25be154cbf2289076e64d1eab", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" }, "conflict": { "doctrine/dbal": "<3.6", @@ -4509,13 +4478,13 @@ "require-dev": { "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5", - "symfony/clock": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0" + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4543,7 +4512,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.3.3" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.8" }, "funding": [ { @@ -4563,29 +4532,29 @@ "type": "tidelift" } ], - "time": "2025-08-20T08:04:18+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.3", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b" + "reference": "23486f59234c6fd6e8f1bec97124f3829d686627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b", - "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/23486f59234c6fd6e8f1bec97124f3829d686627", + "reference": "23486f59234c6fd6e8f1bec97124f3829d686627", "shasum": "" }, "require": { "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0", - "symfony/event-dispatcher": "^7.3", - "symfony/http-foundation": "^7.3", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { @@ -4595,6 +4564,7 @@ "symfony/console": "<6.4", "symfony/dependency-injection": "<6.4", "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", "symfony/form": "<6.4", "symfony/http-client": "<6.4", "symfony/http-client-contracts": "<2.5", @@ -4612,27 +4582,27 @@ }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^6.4|^7.0", - "symfony/clock": "^6.4|^7.0", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/css-selector": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4.1|^7.0.1|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^7.1", - "symfony/routing": "^6.4|^7.0", - "symfony/serializer": "^7.1", - "symfony/stopwatch": "^6.4|^7.0", - "symfony/translation": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^6.4|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0", - "symfony/var-exporter": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "type": "library", @@ -4661,7 +4631,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.3.3" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.10" }, "funding": [ { @@ -4681,20 +4651,20 @@ "type": "tidelift" } ], - "time": "2025-08-29T08:23:45+00:00" + "time": "2026-05-06T12:07:34+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.3", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575" + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575", - "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f6ea532250b476bfc1b56699b388a1bdbf168f62", + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62", "shasum": "" }, "require": { @@ -4702,8 +4672,8 @@ "php": ">=8.2", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/mime": "^7.2", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -4714,10 +4684,10 @@ "symfony/twig-bridge": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/twig-bridge": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -4745,7 +4715,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.3" + "source": "https://github.com/symfony/mailer/tree/v7.4.8" }, "funding": [ { @@ -4765,43 +4735,44 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/mime", - "version": "v7.3.2", + "version": "v7.4.9", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" + "reference": "2d550c4758ba4c47519a6667c36553d535705b0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", - "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "url": "https://api.github.com/repos/symfony/mime/zipball/2d550c4758ba4c47519a6667c36553d535705b0c", + "reference": "2d550c4758ba4c47519a6667c36553d535705b0c", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" }, "conflict": { "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<3.2.2", - "phpdocumentor/type-resolver": "<1.4.0", + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/property-access": "^6.4|^7.0", - "symfony/property-info": "^6.4|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" }, "type": "library", "autoload": { @@ -4833,7 +4804,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.2" + "source": "https://github.com/symfony/mime/tree/v7.4.9" }, "funding": [ { @@ -4853,20 +4824,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2026-04-29T13:21:53+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "reference": "141046a8f9477948ff284fa65be2095baafb94f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2", + "reference": "141046a8f9477948ff284fa65be2095baafb94f2", "shasum": "" }, "require": { @@ -4916,7 +4887,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0" }, "funding": [ { @@ -4936,20 +4907,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + "reference": "4864388bfbd3001ce88e234fab652acd91fdc57e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/4864388bfbd3001ce88e234fab652acd91fdc57e", + "reference": "4864388bfbd3001ce88e234fab652acd91fdc57e", "shasum": "" }, "require": { @@ -4998,7 +4969,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.37.0" }, "funding": [ { @@ -5018,11 +4989,11 @@ "type": "tidelift" } ], - "time": "2025-06-27T09:58:17+00:00" + "time": "2026-04-26T13:13:48+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -5085,7 +5056,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.37.0" }, "funding": [ { @@ -5109,7 +5080,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -5170,7 +5141,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.37.0" }, "funding": [ { @@ -5194,16 +5165,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6a21eb99c6973357967f6ce3708cd55a6bec6315", + "reference": "6a21eb99c6973357967f6ce3708cd55a6bec6315", "shasum": "" }, "require": { @@ -5255,7 +5226,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.37.0" }, "funding": [ { @@ -5275,20 +5246,20 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2026-04-10T17:25:58+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", - "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", + "reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "shasum": "" }, "require": { @@ -5339,7 +5310,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" }, "funding": [ { @@ -5359,20 +5330,20 @@ "type": "tidelift" } ], - "time": "2025-01-02T08:10:11+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/3600c2cb22399e25bb226e4a135ce91eeb2a6149", + "reference": "3600c2cb22399e25bb226e4a135ce91eeb2a6149", "shasum": "" }, "require": { @@ -5419,7 +5390,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.37.0" }, "funding": [ { @@ -5439,20 +5410,20 @@ "type": "tidelift" } ], - "time": "2025-07-08T02:45:35+00:00" + "time": "2026-04-10T17:25:58+00:00" }, { "name": "symfony/polyfill-php84", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/88486db2c389b290bf87ff1de7ebc1e13e42bb06", + "reference": "88486db2c389b290bf87ff1de7ebc1e13e42bb06", "shasum": "" }, "require": { @@ -5499,7 +5470,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php84/tree/v1.37.0" }, "funding": [ { @@ -5519,20 +5490,20 @@ "type": "tidelift" } ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2026-04-10T18:47:49+00:00" }, { "name": "symfony/polyfill-php85", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php85.git", - "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" + "reference": "fcfa4973a9917cef23f2e38774da74a2b7d115ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", - "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/fcfa4973a9917cef23f2e38774da74a2b7d115ee", + "reference": "fcfa4973a9917cef23f2e38774da74a2b7d115ee", "shasum": "" }, "require": { @@ -5579,7 +5550,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.37.0" }, "funding": [ { @@ -5599,20 +5570,20 @@ "type": "tidelift" } ], - "time": "2025-06-23T16:12:55+00:00" + "time": "2026-04-26T13:10:57+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.33.0", + "version": "v1.37.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", - "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/26dfec253c4cf3e51b541b52ddf7e42cb0908e94", + "reference": "26dfec253c4cf3e51b541b52ddf7e42cb0908e94", "shasum": "" }, "require": { @@ -5662,7 +5633,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.37.0" }, "funding": [ { @@ -5682,20 +5653,20 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2026-04-10T16:19:22+00:00" }, { "name": "symfony/process", - "version": "v7.3.3", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "32241012d521e2e8a9d713adb0812bb773b907f1" + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1", - "reference": "32241012d521e2e8a9d713adb0812bb773b907f1", + "url": "https://api.github.com/repos/symfony/process/zipball/60f19cd3badc8de688421e21e4305eba50f8089a", + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a", "shasum": "" }, "require": { @@ -5727,7 +5698,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.3" + "source": "https://github.com/symfony/process/tree/v7.4.8" }, "funding": [ { @@ -5747,20 +5718,20 @@ "type": "tidelift" } ], - "time": "2025-08-18T09:42:54+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/routing", - "version": "v7.3.2", + "version": "v7.4.9", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4" + "reference": "287771d8bc86eacb30678dd10eda6c64a859951f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/7614b8ca5fa89b9cd233e21b627bfc5774f586e4", - "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4", + "url": "https://api.github.com/repos/symfony/routing/zipball/287771d8bc86eacb30678dd10eda6c64a859951f", + "reference": "287771d8bc86eacb30678dd10eda6c64a859951f", "shasum": "" }, "require": { @@ -5774,11 +5745,11 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/expression-language": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/yaml": "^6.4|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5812,7 +5783,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.2" + "source": "https://github.com/symfony/routing/tree/v7.4.9" }, "funding": [ { @@ -5832,20 +5803,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T11:36:08+00:00" + "time": "2026-04-22T15:21:55+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", "shasum": "" }, "require": { @@ -5863,7 +5834,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -5899,7 +5870,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" }, "funding": [ { @@ -5910,31 +5881,36 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2026-03-28T09:44:51+00:00" }, { "name": "symfony/string", - "version": "v7.3.3", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c" + "reference": "114ac57257d75df748eda23dd003878080b8e688" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", - "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", + "url": "https://api.github.com/repos/symfony/string/zipball/114ac57257d75df748eda23dd003878080b8e688", + "reference": "114ac57257d75df748eda23dd003878080b8e688", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -5942,12 +5918,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/emoji": "^7.1", - "symfony/error-handler": "^6.4|^7.0", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5986,7 +5961,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.3" + "source": "https://github.com/symfony/string/tree/v7.4.8" }, "funding": [ { @@ -6006,27 +5981,27 @@ "type": "tidelift" } ], - "time": "2025-08-25T06:35:40+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/translation", - "version": "v7.3.3", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "e0837b4cbcef63c754d89a4806575cada743a38d" + "reference": "ada7578c30dd5feaa8259cff3e885069ea81ddde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d", - "reference": "e0837b4cbcef63c754d89a4806575cada743a38d", + "url": "https://api.github.com/repos/symfony/translation/zipball/ada7578c30dd5feaa8259cff3e885069ea81ddde", + "reference": "ada7578c30dd5feaa8259cff3e885069ea81ddde", "shasum": "" }, "require": { "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "symfony/translation-contracts": "^2.5.3|^3.3" }, "conflict": { "nikic/php-parser": "<5.0", @@ -6045,17 +6020,17 @@ "require-dev": { "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^6.4|^7.0", - "symfony/console": "^6.4|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/finder": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^6.4|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6086,7 +6061,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.3" + "source": "https://github.com/symfony/translation/tree/v7.4.10" }, "funding": [ { @@ -6106,20 +6081,20 @@ "type": "tidelift" } ], - "time": "2025-08-01T21:02:37+00:00" + "time": "2026-05-06T11:19:24+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.0", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + "reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/0ab302977a952b42fd51475c4ebac81f8da0a95d", + "reference": "0ab302977a952b42fd51475c4ebac81f8da0a95d", "shasum": "" }, "require": { @@ -6132,7 +6107,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "3.7-dev" } }, "autoload": { @@ -6168,7 +6143,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.7.0" }, "funding": [ { @@ -6179,25 +6154,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-27T08:32:26+00:00" + "time": "2026-01-05T13:30:16+00:00" }, { "name": "symfony/uid", - "version": "v7.3.1", + "version": "v7.4.9", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb" + "reference": "2676b524340abcfe4d6151ec698463cebafee439" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/a69f69f3159b852651a6bf45a9fdd149520525bb", - "reference": "a69f69f3159b852651a6bf45a9fdd149520525bb", + "url": "https://api.github.com/repos/symfony/uid/zipball/2676b524340abcfe4d6151ec698463cebafee439", + "reference": "2676b524340abcfe4d6151ec698463cebafee439", "shasum": "" }, "require": { @@ -6205,7 +6184,7 @@ "symfony/polyfill-uuid": "^1.15" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6242,7 +6221,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.3.1" + "source": "https://github.com/symfony/uid/tree/v7.4.9" }, "funding": [ { @@ -6253,25 +6232,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2026-04-30T15:19:22+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.3.3", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f" + "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", - "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9510c3966f749a1d1ff0059e1eabef6cc621e7fd", + "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd", "shasum": "" }, "require": { @@ -6283,10 +6266,10 @@ "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/uid": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", "twig/twig": "^3.12" }, "bin": [ @@ -6325,7 +6308,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.3" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.8" }, "funding": [ { @@ -6345,20 +6328,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T11:49:31+00:00" + "time": "2026-03-30T13:44:50+00:00" }, { "name": "thecodingmachine/safe", - "version": "v3.3.0", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/thecodingmachine/safe.git", - "reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236" + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/2cdd579eeaa2e78e51c7509b50cc9fb89a956236", - "reference": "2cdd579eeaa2e78e51c7509b50cc9fb89a956236", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", "shasum": "" }, "require": { @@ -6468,7 +6451,7 @@ "description": "PHP core functions that throw exceptions instead of returning FALSE on error", "support": { "issues": "https://github.com/thecodingmachine/safe/issues", - "source": "https://github.com/thecodingmachine/safe/tree/v3.3.0" + "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" }, "funding": [ { @@ -6479,32 +6462,36 @@ "url": "https://github.com/shish", "type": "github" }, + { + "url": "https://github.com/silasjoisten", + "type": "github" + }, { "url": "https://github.com/staabm", "type": "github" } ], - "time": "2025-05-14T06:15:44+00:00" + "time": "2026-02-04T18:08:13+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "v2.3.0", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", - "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "php": "^7.4 || ^8.0", - "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^2.0", @@ -6537,32 +6524,32 @@ "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", "support": { "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", - "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.4.0" }, - "time": "2024-12-21T16:25:41+00:00" + "time": "2025-12-02T11:56:42+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.6.2", + "version": "v5.6.3", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + "reference": "955e7815d677a3eaa7075231212f2110983adecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", - "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.1.3", + "graham-campbell/result-type": "^1.1.4", "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.3", - "symfony/polyfill-ctype": "^1.24", - "symfony/polyfill-mbstring": "^1.24", - "symfony/polyfill-php80": "^1.24" + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", @@ -6611,7 +6598,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" }, "funding": [ { @@ -6623,27 +6610,27 @@ "type": "tidelift" } ], - "time": "2025-04-30T23:37:27+00:00" + "time": "2025-12-27T19:49:13+00:00" }, { "name": "voku/portable-ascii", - "version": "2.0.3", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/voku/portable-ascii.git", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" + "reference": "8e1051fe39379367aecf014f41744ce7539a856f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", - "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/8e1051fe39379367aecf014f41744ce7539a856f", + "reference": "8e1051fe39379367aecf014f41744ce7539a856f", "shasum": "" }, "require": { - "php": ">=7.0.0" + "php": ">=7.1.0" }, "require-dev": { - "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + "phpunit/phpunit": "~8.5 || ~9.6 || ~10.5 || ~11.5" }, "suggest": { "ext-intl": "Use Intl for transliterator_transliterate() support" @@ -6673,7 +6660,7 @@ ], "support": { "issues": "https://github.com/voku/portable-ascii/issues", - "source": "https://github.com/voku/portable-ascii/tree/2.0.3" + "source": "https://github.com/voku/portable-ascii/tree/2.1.1" }, "funding": [ { @@ -6697,7 +6684,7 @@ "type": "tidelift" } ], - "time": "2024-11-21T01:49:47+00:00" + "time": "2026-04-26T05:33:54+00:00" }, { "name": "webklex/php-imap", @@ -6779,64 +6766,6 @@ } ], "time": "2025-04-25T06:02:37+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" - }, - "time": "2022-06-03T18:03:27+00:00" } ], "packages-dev": [ @@ -7027,37 +6956,38 @@ }, { "name": "laravel/pail", - "version": "v1.2.3", + "version": "v1.2.6", "source": { "type": "git", "url": "https://github.com/laravel/pail.git", - "reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a" + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pail/zipball/8cc3d575c1f0e57eeb923f366a37528c50d2385a", - "reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a", + "url": "https://api.github.com/repos/laravel/pail/zipball/aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", "shasum": "" }, "require": { "ext-mbstring": "*", - "illuminate/console": "^10.24|^11.0|^12.0", - "illuminate/contracts": "^10.24|^11.0|^12.0", - "illuminate/log": "^10.24|^11.0|^12.0", - "illuminate/process": "^10.24|^11.0|^12.0", - "illuminate/support": "^10.24|^11.0|^12.0", + "illuminate/console": "^10.24|^11.0|^12.0|^13.0", + "illuminate/contracts": "^10.24|^11.0|^12.0|^13.0", + "illuminate/log": "^10.24|^11.0|^12.0|^13.0", + "illuminate/process": "^10.24|^11.0|^12.0|^13.0", + "illuminate/support": "^10.24|^11.0|^12.0|^13.0", "nunomaduro/termwind": "^1.15|^2.0", "php": "^8.2", - "symfony/console": "^6.0|^7.0" + "symfony/console": "^6.0|^7.0|^8.0" }, "require-dev": { - "laravel/framework": "^10.24|^11.0|^12.0", + "laravel/framework": "^10.24|^11.0|^12.0|^13.0", "laravel/pint": "^1.13", - "orchestra/testbench-core": "^8.13|^9.0|^10.0", - "pestphp/pest": "^2.20|^3.0", - "pestphp/pest-plugin-type-coverage": "^2.3|^3.0", + "orchestra/testbench-core": "^8.13|^9.17|^10.8|^11.0", + "pestphp/pest": "^2.20|^3.0|^4.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0|^4.0", "phpstan/phpstan": "^1.12.27", - "symfony/var-dumper": "^6.3|^7.0" + "symfony/var-dumper": "^6.3|^7.0|^8.0", + "symfony/yaml": "^6.3|^7.0|^8.0" }, "type": "library", "extra": { @@ -7102,20 +7032,20 @@ "issues": "https://github.com/laravel/pail/issues", "source": "https://github.com/laravel/pail" }, - "time": "2025-06-05T13:55:57+00:00" + "time": "2026-02-09T13:44:54+00:00" }, { "name": "laravel/pint", - "version": "v1.25.1", + "version": "v1.29.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9" + "reference": "0770e9b7fafd50d4586881d456d6eb41c9247a80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/5016e263f95d97670d71b9a987bd8996ade6d8d9", - "reference": "5016e263f95d97670d71b9a987bd8996ade6d8d9", + "url": "https://api.github.com/repos/laravel/pint/zipball/0770e9b7fafd50d4586881d456d6eb41c9247a80", + "reference": "0770e9b7fafd50d4586881d456d6eb41c9247a80", "shasum": "" }, "require": { @@ -7126,13 +7056,14 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.87.2", - "illuminate/view": "^11.46.0", - "larastan/larastan": "^3.7.1", - "laravel-zero/framework": "^11.45.0", + "friendsofphp/php-cs-fixer": "^3.95.1", + "illuminate/view": "^12.56.0", + "larastan/larastan": "^3.9.6", + "laravel-zero/framework": "^12.1.0", "mockery/mockery": "^1.6.12", - "nunomaduro/termwind": "^2.3.1", - "pestphp/pest": "^2.36.0" + "nunomaduro/termwind": "^2.4.0", + "pestphp/pest": "^3.8.6", + "shipfastlabs/agent-detector": "^1.1.3" }, "bin": [ "builds/pint" @@ -7158,6 +7089,7 @@ "description": "An opinionated code formatter for PHP.", "homepage": "https://laravel.com", "keywords": [ + "dev", "format", "formatter", "lint", @@ -7168,33 +7100,33 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2025-09-19T02:57:12+00:00" + "time": "2026-04-20T15:26:14+00:00" }, { "name": "laravel/sail", - "version": "v1.46.0", + "version": "v1.58.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e" + "reference": "2e5e968138ca52ed87d712449697a8364d73b466" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e", - "reference": "eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e", + "url": "https://api.github.com/repos/laravel/sail/zipball/2e5e968138ca52ed87d712449697a8364d73b466", + "reference": "2e5e968138ca52ed87d712449697a8364d73b466", "shasum": "" }, "require": { - "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0", - "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0", - "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0", "php": "^8.0", - "symfony/console": "^6.0|^7.0", - "symfony/yaml": "^6.0|^7.0" + "symfony/console": "^6.0|^7.0|^8.0", + "symfony/yaml": "^6.0|^7.0|^8.0" }, "require-dev": { - "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", - "phpstan/phpstan": "^1.10" + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0", + "phpstan/phpstan": "^2.0" }, "bin": [ "bin/sail" @@ -7231,7 +7163,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2025-09-23T13:44:39+00:00" + "time": "2026-04-27T13:38:34+00:00" }, { "name": "mockery/mockery", @@ -7378,39 +7310,36 @@ }, { "name": "nunomaduro/collision", - "version": "v8.8.2", + "version": "v8.9.4", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb" + "reference": "716af8f95a470e9094cfca09ed897b023be191a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", - "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/716af8f95a470e9094cfca09ed897b023be191a5", + "reference": "716af8f95a470e9094cfca09ed897b023be191a5", "shasum": "" }, "require": { - "filp/whoops": "^2.18.1", - "nunomaduro/termwind": "^2.3.1", + "filp/whoops": "^2.18.4", + "nunomaduro/termwind": "^2.4.0", "php": "^8.2.0", - "symfony/console": "^7.3.0" + "symfony/console": "^7.4.8 || ^8.0.8" }, "conflict": { - "laravel/framework": "<11.44.2 || >=13.0.0", - "phpunit/phpunit": "<11.5.15 || >=13.0.0" + "laravel/framework": "<11.48.0 || >=14.0.0", + "phpunit/phpunit": "<11.5.50 || >=14.0.0" }, "require-dev": { - "brianium/paratest": "^7.8.3", - "larastan/larastan": "^3.4.2", - "laravel/framework": "^11.44.2 || ^12.18", - "laravel/pint": "^1.22.1", - "laravel/sail": "^1.43.1", - "laravel/sanctum": "^4.1.1", - "laravel/tinker": "^2.10.1", - "orchestra/testbench-core": "^9.12.0 || ^10.4", - "pestphp/pest": "^3.8.2", - "sebastian/environment": "^7.2.1 || ^8.0" + "brianium/paratest": "^7.8.5", + "larastan/larastan": "^3.9.6", + "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.5.0", + "laravel/pint": "^1.29.1", + "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.2.1", + "pestphp/pest": "^3.8.5 || ^4.4.3 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.0.4 || ^9.3.0" }, "type": "library", "extra": { @@ -7473,7 +7402,7 @@ "type": "patreon" } ], - "time": "2025-06-25T02:12:12+00:00" + "time": "2026-04-21T14:04:20+00:00" }, { "name": "phar-io/manifest", @@ -7595,35 +7524,35 @@ }, { "name": "phpunit/php-code-coverage", - "version": "11.0.11", + "version": "11.0.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4" + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", - "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^5.4.0", + "nikic/php-parser": "^5.7.0", "php": ">=8.2", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-text-template": "^4.0.1", "sebastian/code-unit-reverse-lookup": "^4.0.1", "sebastian/complexity": "^4.0.1", - "sebastian/environment": "^7.2.0", + "sebastian/environment": "^7.2.1", "sebastian/lines-of-code": "^3.0.1", "sebastian/version": "^5.0.2", - "theseer/tokenizer": "^1.2.3" + "theseer/tokenizer": "^1.3.1" }, "require-dev": { - "phpunit/phpunit": "^11.5.2" + "phpunit/phpunit": "^11.5.46" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", @@ -7661,7 +7590,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.11" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" }, "funding": [ { @@ -7681,32 +7610,32 @@ "type": "tidelift" } ], - "time": "2025-08-27T14:37:49+00:00" + "time": "2025-12-24T07:01:01+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -7734,15 +7663,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2026-02-02T13:52:54+00:00" }, { "name": "phpunit/php-invoker", @@ -7930,16 +7871,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.41", + "version": "11.5.55", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b42782bcb947d2c197aea42ce9714ee2d974b283" + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b42782bcb947d2c197aea42ce9714ee2d974b283", - "reference": "b42782bcb947d2c197aea42ce9714ee2d974b283", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", "shasum": "" }, "require": { @@ -7953,19 +7894,20 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.11", - "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.2", + "sebastian/comparator": "^6.3.3", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.1", "sebastian/exporter": "^6.3.2", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", "sebastian/type": "^5.1.3", "sebastian/version": "^5.0.2", "staabm/side-effects-detector": "^1.0.5" @@ -8011,7 +7953,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.41" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" }, "funding": [ { @@ -8035,7 +7977,7 @@ "type": "tidelift" } ], - "time": "2025-09-24T06:32:10+00:00" + "time": "2026-02-18T12:37:06+00:00" }, { "name": "sebastian/cli-parser", @@ -8209,16 +8151,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.2", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { @@ -8277,7 +8219,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, "funding": [ { @@ -8297,7 +8239,7 @@ "type": "tidelift" } ], - "time": "2025-08-10T08:07:46+00:00" + "time": "2026-01-24T09:26:40+00:00" }, { "name": "sebastian/complexity", @@ -9077,28 +9019,28 @@ }, { "name": "symfony/yaml", - "version": "v7.3.3", + "version": "v7.4.10", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "d4f4a66866fe2451f61296924767280ab5732d9d" + "reference": "c660d6538545a3e8e65a5621ee3d7a6d352892c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/d4f4a66866fe2451f61296924767280ab5732d9d", - "reference": "d4f4a66866fe2451f61296924767280ab5732d9d", + "url": "https://api.github.com/repos/symfony/yaml/zipball/c660d6538545a3e8e65a5621ee3d7a6d352892c7", + "reference": "c660d6538545a3e8e65a5621ee3d7a6d352892c7", "shasum": "" }, "require": { "php": ">=8.2", - "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^6.4|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -9129,7 +9071,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.3.3" + "source": "https://github.com/symfony/yaml/tree/v7.4.10" }, "funding": [ { @@ -9149,20 +9091,20 @@ "type": "tidelift" } ], - "time": "2025-08-27T11:34:33+00:00" + "time": "2026-05-05T08:01:55+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", "shasum": "" }, "require": { @@ -9191,7 +9133,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" }, "funding": [ { @@ -9199,17 +9141,17 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-17T20:03:58+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.2" }, - "platform-dev": [], - "plugin-api-version": "2.6.0" + "platform-dev": {}, + "plugin-api-version": "2.9.0" } diff --git a/thanasoft-back/config/database.php b/thanasoft-back/config/database.php index 53dcae0..7d61b4c 100644 --- a/thanasoft-back/config/database.php +++ b/thanasoft-back/config/database.php @@ -57,7 +57,7 @@ return [ 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, - 'engine' => null, + 'engine' => env('DB_ENGINE', 'InnoDB'), 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], @@ -77,7 +77,7 @@ return [ 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, - 'engine' => null, + 'engine' => env('DB_ENGINE', 'InnoDB'), 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], diff --git a/thanasoft-back/database/migrations/2025_10_29_103700_add_fournisseur_to_contacts_table.php b/thanasoft-back/database/migrations/2025_10_29_103700_add_fournisseur_to_contacts_table.php index 52dd402..b2806ce 100644 --- a/thanasoft-back/database/migrations/2025_10_29_103700_add_fournisseur_to_contacts_table.php +++ b/thanasoft-back/database/migrations/2025_10_29_103700_add_fournisseur_to_contacts_table.php @@ -14,7 +14,13 @@ return new class extends Migration Schema::table('contacts', function (Blueprint $table) { // Make client_id nullable and remove cascade $table->dropForeign(['client_id']); - $table->foreignId('client_id')->nullable()->change(); + }); + + Schema::table('contacts', function (Blueprint $table) { + $table->unsignedBigInteger('client_id')->nullable()->change(); + }); + + Schema::table('contacts', function (Blueprint $table) { $table->foreign('client_id')->references('id')->on('clients')->onDelete('set null'); // Add fournisseur_id @@ -34,7 +40,13 @@ return new class extends Migration // Restore client_id to not nullable with cascade $table->dropForeign(['client_id']); - $table->foreignId('client_id')->change(); + }); + + Schema::table('contacts', function (Blueprint $table) { + $table->unsignedBigInteger('client_id')->nullable(false)->change(); + }); + + Schema::table('contacts', function (Blueprint $table) { $table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); }); } diff --git a/thanasoft-back/database/migrations/2026_05_08_120000_create_leaves_table.php b/thanasoft-back/database/migrations/2026_05_08_120000_create_leaves_table.php new file mode 100644 index 0000000..47fd1fc --- /dev/null +++ b/thanasoft-back/database/migrations/2026_05_08_120000_create_leaves_table.php @@ -0,0 +1,39 @@ +id(); + $table->foreignId('employee_id')->constrained()->cascadeOnDelete(); + $table->enum('type', ['conge', 'repos', 'feriee']); + $table->enum('status', ['pending', 'approved', 'rejected', 'cancelled'])->default('pending'); + $table->date('start_date'); + $table->date('end_date'); + $table->text('reason')->nullable(); + $table->text('notes')->nullable(); + $table->foreignId('approved_by')->nullable()->constrained('users')->nullOnDelete(); + $table->timestamp('approved_at')->nullable(); + $table->timestamps(); + + $table->index(['employee_id', 'status']); + $table->index(['start_date', 'end_date']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('leaves'); + } +}; \ No newline at end of file diff --git a/thanasoft-back/database/migrations/2026_05_08_121000_create_leave_histories_table.php b/thanasoft-back/database/migrations/2026_05_08_121000_create_leave_histories_table.php new file mode 100644 index 0000000..5ed0a16 --- /dev/null +++ b/thanasoft-back/database/migrations/2026_05_08_121000_create_leave_histories_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('leave_id')->constrained()->cascadeOnDelete(); + $table->string('old_status', 32)->nullable(); + $table->string('new_status', 32); + $table->foreignId('changed_by')->nullable()->constrained('users')->nullOnDelete(); + $table->timestamp('changed_at')->useCurrent(); + $table->text('comment')->nullable(); + + $table->index(['leave_id', 'changed_at']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('leave_histories'); + } +}; \ No newline at end of file diff --git a/thanasoft-back/database/seeders/AvoirSeeder.php b/thanasoft-back/database/seeders/AvoirSeeder.php new file mode 100644 index 0000000..ec4d1b2 --- /dev/null +++ b/thanasoft-back/database/seeders/AvoirSeeder.php @@ -0,0 +1,72 @@ +orderByRaw('RAND()') + ->limit(22) + ->get(); + + if ($invoices->isEmpty()) { + $this->command->warn('AvoirSeeder: aucune facture éligible trouvée — skip.'); + return; + } + + // Status pool: mostly emis / some applique + $statusPool = array_merge( + array_fill(0, 13, 'emis'), + array_fill(0, 9, 'applique') + ); + shuffle($statusPool); + + foreach ($invoices as $idx => $invoice) { + $reason = self::REASON_TYPES[array_rand(self::REASON_TYPES)]; + $status = $statusPool[$idx % count($statusPool)]; + $avoirDate = $invoice->invoice_date + ->copy() + ->addDays(rand(5, 60)) + ->format('Y-m-d'); + + // Partial or total credit + $fraction = ($reason === 'remboursement_total') ? 1.0 : round(rand(20, 80) / 100, 2); + $totalHt = round((float) $invoice->total_ht * $fraction, 2); + $totalTva = round($totalHt * 0.20, 2); + $totalTtc = round($totalHt + $totalTva, 2); + + Avoir::create([ + 'client_id' => $invoice->client_id, + 'invoice_id' => $invoice->id, + 'status' => $status, + 'avoir_date' => $avoirDate, + 'currency' => 'EUR', + 'total_ht' => $totalHt, + 'total_tva' => $totalTva, + 'total_ttc' => $totalTtc, + 'reason_type' => $reason, + 'reason_description' => null, + 'refund_status' => 'non_rembourse', + ]); + } + + $this->command->info('AvoirSeeder: ' . $invoices->count() . ' avoirs créés.'); + } +} diff --git a/thanasoft-back/database/seeders/DatabaseSeeder.php b/thanasoft-back/database/seeders/DatabaseSeeder.php index 34ec56d..e9b34b3 100644 --- a/thanasoft-back/database/seeders/DatabaseSeeder.php +++ b/thanasoft-back/database/seeders/DatabaseSeeder.php @@ -25,5 +25,10 @@ class DatabaseSeeder extends Seeder $this->call(ContactSeeder::class); $this->call(DeceasedSeeder::class); $this->call(InterventionSeeder::class); + + // ── Financial data ──────────────────────────────────────────────────── + $this->call(QuoteSeeder::class); + $this->call(InvoiceSeeder::class); + $this->call(AvoirSeeder::class); } } diff --git a/thanasoft-back/database/seeders/InvoiceSeeder.php b/thanasoft-back/database/seeders/InvoiceSeeder.php new file mode 100644 index 0000000..c4fd9a6 --- /dev/null +++ b/thanasoft-back/database/seeders/InvoiceSeeder.php @@ -0,0 +1,152 @@ +toArray(); + $products = DB::table('products')->select('id', 'prix_unitaire')->get()->keyBy('id'); + $productIds = $products->keys()->toArray(); + + if (empty($clientIds) || empty($productIds)) { + $this->command->warn('InvoiceSeeder: aucun client ou produit trouvé — skip.'); + return; + } + + // ── 1. Invoices liées à des devis acceptés ──────────────────────────── + $acceptedQuotes = Quote::where('status', 'accepte') + ->orderBy('id') + ->limit(35) + ->get(); + + foreach ($acceptedQuotes as $quote) { + $invoiceDate = $quote->quote_date->copy()->addDays(rand(2, 10))->format('Y-m-d'); + $dueDate = date('Y-m-d', strtotime($invoiceDate . ' +30 days')); + + // Statuses for quote-linked invoices (mostly paid) + $s = ['payee', 'payee', 'payee', 'emise', 'envoyee', 'partiellement_payee']; + + Invoice::create([ + 'client_id' => $quote->client_id, + 'source_quote_id' => $quote->id, + 'status' => $s[array_rand($s)], + 'invoice_date' => $invoiceDate, + 'due_date' => $dueDate, + 'currency' => 'EUR', + 'total_ht' => $quote->total_ht, + 'total_tva' => $quote->total_tva, + 'total_ttc' => $quote->total_ttc, + ]); + // Lines are not duplicated — source quote already has them + } + + // ── 2. Invoices autonomes ───────────────────────────────────────────── + // 2024 historical — statuses varied, many paid + $this->createBatch($clientIds, $productIds, $products, [ + 'yearRange' => [[2024, 1, 12]], + 'countPerMonth' => [3, 5], + 'statusPool' => ['payee', 'payee', 'payee', 'emise', 'envoyee', 'partiellement_payee', 'echue'], + ]); + + // 2025 main year — rich dataset + $this->createBatch($clientIds, $productIds, $products, [ + 'yearRange' => [[2025, 1, 12]], + 'countPerMonth' => [4, 7], + 'statusPool' => ['payee', 'payee', 'payee', 'emise', 'envoyee', 'partiellement_payee', 'echue', 'echue'], + ]); + + // 2026 Jan-Apr — no echue (due dates not yet past) + $this->createBatch($clientIds, $productIds, $products, [ + 'yearRange' => [[2026, 1, 4]], + 'countPerMonth' => [4, 6], + 'statusPool' => ['payee', 'payee', 'emise', 'envoyee', 'partiellement_payee'], + ]); + + // 2026 May 1-8 — recent, mostly emise + $this->createBatch($clientIds, $productIds, $products, [ + 'yearRange' => [[2026, 5, 5]], + 'countPerMonth' => [4, 6], + 'maxDay' => 8, + 'statusPool' => ['payee', 'emise', 'emise', 'envoyee'], + ]); + + $total = Invoice::count(); + $this->command->info("InvoiceSeeder: {$total} factures au total."); + } + + // ───────────────────────────────────────────────────────────────────────── + + private function createBatch( + array $clientIds, + array $productIds, + \Illuminate\Support\Collection $products, + array $opts + ): void { + foreach ($opts['yearRange'] as [$year, $startM, $endM]) { + for ($m = $startM; $m <= $endM; $m++) { + $maxDay = $opts['maxDay'] ?? 28; + $count = rand(...$opts['countPerMonth']); + + for ($i = 0; $i < $count; $i++) { + $invoiceDate = sprintf('%04d-%02d-%02d', $year, $m, rand(1, $maxDay)); + $status = $opts['statusPool'][array_rand($opts['statusPool'])]; + + // due_date + if ($status === 'echue') { + $dueDate = date('Y-m-d', strtotime($invoiceDate . ' +10 days')); + } else { + $dueDate = date('Y-m-d', strtotime($invoiceDate . ' +30 days')); + } + + $clientId = $clientIds[array_rand($clientIds)]; + + // Build lines + $lineData = []; + $totalHt = 0.0; + for ($l = 0, $nl = rand(1, 3); $l < $nl; $l++) { + $pid = $productIds[array_rand($productIds)]; + $unitPrice = (float) ($products->get($pid)->prix_unitaire ?? 150.00); + $qty = rand(1, 3); + $lineHt = round($unitPrice * $qty, 2); + $totalHt += $lineHt; + $lineData[] = [ + 'product_id' => $pid, + 'description' => 'Prestation funéraire', + 'qty_base' => $qty, + 'unit_price' => $unitPrice, + 'discount_pct' => 0, + 'total_ht' => $lineHt, + ]; + } + + $totalTva = round($totalHt * 0.20, 2); + $totalTtc = round($totalHt + $totalTva, 2); + + $invoice = Invoice::create([ + 'client_id' => $clientId, + 'status' => $status, + 'invoice_date' => $invoiceDate, + 'due_date' => $dueDate, + 'currency' => 'EUR', + 'total_ht' => $totalHt, + 'total_tva' => $totalTva, + 'total_ttc' => $totalTtc, + ]); + + foreach ($lineData as $line) { + InvoiceLine::create(array_merge($line, ['invoice_id' => $invoice->id])); + } + } + } + } + } +} diff --git a/thanasoft-back/database/seeders/QuoteSeeder.php b/thanasoft-back/database/seeders/QuoteSeeder.php new file mode 100644 index 0000000..a694f20 --- /dev/null +++ b/thanasoft-back/database/seeders/QuoteSeeder.php @@ -0,0 +1,105 @@ +toArray(); + $products = DB::table('products')->select('id', 'prix_unitaire')->get()->keyBy('id'); + $productIds = $products->keys()->toArray(); + + if (empty($clientIds) || empty($productIds)) { + $this->command->warn('QuoteSeeder: aucun client ou produit trouvé — skip.'); + return; + } + + // ── Statuses ────────────────────────────────────────────────────────── + $statusPool = array_merge( + array_fill(0, 40, 'accepte'), + array_fill(0, 18, 'envoye'), + array_fill(0, 8, 'brouillon'), + array_fill(0, 10, 'refuse'), + array_fill(0, 7, 'expire') + ); + shuffle($statusPool); + + // ── Date entries : 2024 + 2025 + 2026 Jan-May ──────────────────────── + $entries = []; + + // 2024 (historical) + for ($m = 1; $m <= 12; $m++) { + for ($i = 0, $n = rand(2, 4); $i < $n; $i++) { + $entries[] = sprintf('2024-%02d-%02d', $m, rand(1, 28)); + } + } + // 2025 + for ($m = 1; $m <= 12; $m++) { + for ($i = 0, $n = rand(3, 5); $i < $n; $i++) { + $entries[] = sprintf('2025-%02d-%02d', $m, rand(1, 28)); + } + } + // 2026 Jan-May + for ($m = 1; $m <= 5; $m++) { + $maxDay = ($m === 5) ? 8 : 28; + for ($i = 0, $n = rand(3, 5); $i < $n; $i++) { + $entries[] = sprintf('2026-%02d-%02d', $m, rand(1, $maxDay)); + } + } + + shuffle($entries); + + // ── Create quotes ───────────────────────────────────────────────────── + foreach ($entries as $idx => $quoteDate) { + $status = $statusPool[$idx % count($statusPool)]; + $clientId = $clientIds[array_rand($clientIds)]; + $validUntil = date('Y-m-d', strtotime($quoteDate . ' +30 days')); + + // Build lines + $lineData = []; + $totalHt = 0.0; + for ($l = 0, $nl = rand(1, 3); $l < $nl; $l++) { + $pid = $productIds[array_rand($productIds)]; + $unitPrice = (float) ($products->get($pid)->prix_unitaire ?? 100.00); + $qty = rand(1, 3); + $lineHt = round($unitPrice * $qty, 2); + $totalHt += $lineHt; + $lineData[] = [ + 'product_id' => $pid, + 'description' => 'Prestation funéraire', + 'qty_base' => $qty, + 'unit_price' => $unitPrice, + 'discount_pct' => 0, + 'total_ht' => $lineHt, + ]; + } + + $totalTva = round($totalHt * 0.20, 2); + $totalTtc = round($totalHt + $totalTva, 2); + + $quote = Quote::create([ + 'client_id' => $clientId, + 'status' => $status, + 'quote_date' => $quoteDate, + 'valid_until' => $validUntil, + 'currency' => 'EUR', + 'total_ht' => $totalHt, + 'total_tva' => $totalTva, + 'total_ttc' => $totalTtc, + ]); + + foreach ($lineData as $line) { + QuoteLine::create(array_merge($line, ['quote_id' => $quote->id])); + } + } + + $this->command->info('QuoteSeeder: ' . count($entries) . ' devis créés.'); + } +} diff --git a/thanasoft-back/routes/api.php b/thanasoft-back/routes/api.php index e2ef0c2..57a3429 100644 --- a/thanasoft-back/routes/api.php +++ b/thanasoft-back/routes/api.php @@ -28,7 +28,9 @@ use App\Http\Controllers\Api\GoodsReceiptController; use App\Http\Controllers\Api\UserController; use App\Http\Controllers\Api\VehicleController; use App\Http\Controllers\Api\ConvoyController; +use App\Http\Controllers\Api\LeaveController; use App\Http\Controllers\Api\WebmailController; +use App\Http\Controllers\Api\FinancialStatisticsController; /* @@ -61,6 +63,8 @@ Route::middleware('auth:sanctum')->group(function () { // Client management // IMPORTANT: Specific routes must come before apiResource Route::get('/clients/searchBy', [ClientController::class, 'searchBy']); + Route::get('/clients/statistics', [ClientController::class, 'statistics']); + Route::get('/financial/statistics', [FinancialStatisticsController::class, 'index']); Route::apiResource('clients', ClientController::class); Route::post('client-groups/{id}/assign-clients', [ClientGroupController::class, 'assignClients']); @@ -166,6 +170,7 @@ Route::middleware('auth:sanctum')->group(function () { Route::get('/employees/thanatopractitioners', [EmployeeController::class, 'getThanatopractitioners']); Route::get('/employees/{id}/agenda', [EmployeeController::class, 'agenda']); Route::apiResource('employees', EmployeeController::class); + Route::apiResource('leaves', LeaveController::class); // Thanatopractitioner management Route::get('/thanatopractitioners/search', [ThanatopractitionerController::class, 'searchByEmployeeName']); diff --git a/thanasoft-front/src/components/Atom/Stats/StatKpiCard.vue b/thanasoft-front/src/components/Atom/Stats/StatKpiCard.vue new file mode 100644 index 0000000..a90db9d --- /dev/null +++ b/thanasoft-front/src/components/Atom/Stats/StatKpiCard.vue @@ -0,0 +1,148 @@ + + + diff --git a/thanasoft-front/src/components/Atom/Stats/StatProgressRow.vue b/thanasoft-front/src/components/Atom/Stats/StatProgressRow.vue new file mode 100644 index 0000000..babbf3d --- /dev/null +++ b/thanasoft-front/src/components/Atom/Stats/StatProgressRow.vue @@ -0,0 +1,56 @@ + + + diff --git a/thanasoft-front/src/components/Atom/Stats/StatRankRow.vue b/thanasoft-front/src/components/Atom/Stats/StatRankRow.vue new file mode 100644 index 0000000..7f60545 --- /dev/null +++ b/thanasoft-front/src/components/Atom/Stats/StatRankRow.vue @@ -0,0 +1,37 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/ActiveInactiveCard.vue b/thanasoft-front/src/components/Molecule/Stats/ActiveInactiveCard.vue new file mode 100644 index 0000000..b9d59b5 --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/ActiveInactiveCard.vue @@ -0,0 +1,46 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/AvoirsCard.vue b/thanasoft-front/src/components/Molecule/Stats/AvoirsCard.vue new file mode 100644 index 0000000..27b2f2f --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/AvoirsCard.vue @@ -0,0 +1,63 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/ConversionCard.vue b/thanasoft-front/src/components/Molecule/Stats/ConversionCard.vue new file mode 100644 index 0000000..33a0d11 --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/ConversionCard.vue @@ -0,0 +1,54 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/CriticalInvoicesCard.vue b/thanasoft-front/src/components/Molecule/Stats/CriticalInvoicesCard.vue new file mode 100644 index 0000000..c2259fe --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/CriticalInvoicesCard.vue @@ -0,0 +1,64 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/DistributionCard.vue b/thanasoft-front/src/components/Molecule/Stats/DistributionCard.vue new file mode 100644 index 0000000..5c862b6 --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/DistributionCard.vue @@ -0,0 +1,52 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/GeographicCard.vue b/thanasoft-front/src/components/Molecule/Stats/GeographicCard.vue new file mode 100644 index 0000000..60c3412 --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/GeographicCard.vue @@ -0,0 +1,67 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/RevenueChartCard.vue b/thanasoft-front/src/components/Molecule/Stats/RevenueChartCard.vue new file mode 100644 index 0000000..0dbccba --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/RevenueChartCard.vue @@ -0,0 +1,98 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/TopClientsCard.vue b/thanasoft-front/src/components/Molecule/Stats/TopClientsCard.vue new file mode 100644 index 0000000..aa8f8a2 --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/TopClientsCard.vue @@ -0,0 +1,50 @@ + + + diff --git a/thanasoft-front/src/components/Molecule/Stats/TopDebtorsCard.vue b/thanasoft-front/src/components/Molecule/Stats/TopDebtorsCard.vue new file mode 100644 index 0000000..e6e4b2e --- /dev/null +++ b/thanasoft-front/src/components/Molecule/Stats/TopDebtorsCard.vue @@ -0,0 +1,57 @@ + + + diff --git a/thanasoft-front/src/components/Organism/CRM/ClientStatsDashboard.vue b/thanasoft-front/src/components/Organism/CRM/ClientStatsDashboard.vue new file mode 100644 index 0000000..39a8e1d --- /dev/null +++ b/thanasoft-front/src/components/Organism/CRM/ClientStatsDashboard.vue @@ -0,0 +1,191 @@ + + + diff --git a/thanasoft-front/src/components/Organism/Invoice/FinancialStatsDashboard.vue b/thanasoft-front/src/components/Organism/Invoice/FinancialStatsDashboard.vue new file mode 100644 index 0000000..c0189b1 --- /dev/null +++ b/thanasoft-front/src/components/Organism/Invoice/FinancialStatsDashboard.vue @@ -0,0 +1,182 @@ + + + diff --git a/thanasoft-front/src/components/Organism/Planning/PlanningNewRequestModal.vue b/thanasoft-front/src/components/Organism/Planning/PlanningNewRequestModal.vue index 50ad53c..a213463 100644 --- a/thanasoft-front/src/components/Organism/Planning/PlanningNewRequestModal.vue +++ b/thanasoft-front/src/components/Organism/Planning/PlanningNewRequestModal.vue @@ -41,6 +41,8 @@ v-else-if="creationType === 'leave'" :form="leaveForm" :collaborators="collaborators" + :is-admin="isAdmin" + :current-employee-name="currentEmployeeName" @update:form="$emit('update:leave-form', $event)" @submit="$emit('submit-leave')" @back="$emit('reset-type')" @@ -90,6 +92,14 @@ defineProps({ type: Array, default: () => [], }, + isAdmin: { + type: Boolean, + default: false, + }, + currentEmployeeName: { + type: String, + default: "", + }, leaveForm: { type: Object, required: true, diff --git a/thanasoft-front/src/components/molecules/Employees/EmployeeTable.vue b/thanasoft-front/src/components/molecules/Employees/EmployeeTable.vue index 963bb3d..e1cc9ab 100644 --- a/thanasoft-front/src/components/molecules/Employees/EmployeeTable.vue +++ b/thanasoft-front/src/components/molecules/Employees/EmployeeTable.vue @@ -199,7 +199,7 @@
Affichage de {{ safeFrom }} à {{ safeTo }} sur @@ -622,6 +622,11 @@ onMounted(() => { padding: 3rem 1rem; } +.pagination-footer { + border-top: 1px solid rgba(131, 146, 171, 0.2); + background: #fff; +} + .empty-icon { margin-bottom: 1rem; opacity: 0.5; diff --git a/thanasoft-front/src/components/molecules/Planning/PlanningLeaveRequestForm.vue b/thanasoft-front/src/components/molecules/Planning/PlanningLeaveRequestForm.vue index 1718414..6baba69 100644 --- a/thanasoft-front/src/components/molecules/Planning/PlanningLeaveRequestForm.vue +++ b/thanasoft-front/src/components/molecules/Planning/PlanningLeaveRequestForm.vue @@ -1,21 +1,26 @@