commit a768146f6512be48a937b5a6268bde4502a54886 Author: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Tue Jan 6 15:35:59 2026 -0500 up diff --git a/.blueprint b/.blueprint new file mode 100644 index 0000000..9dddadc --- /dev/null +++ b/.blueprint @@ -0,0 +1,9 @@ +created: + - database/factories/AuthUserFactory.php + - database/migrations/2025_03_06_023837_create_auth_users_table.php + - app/Models/AuthUser.php +models: + User: { name: 'string:100', email: 'string:150 unique', password: string, timestamps: timestamps, relationships: { belongsToMany: Role } } + Role: { name: 'string:50 unique', description: 'string nullable', timestamps: timestamps, relationships: { belongsToMany: User } } + Setting: { logo: 'string nullable', description: 'text nullable', primary_color: 'string nullable', secondary_color: 'string nullable', created_at: 'timestamp nullable', updated_at: 'timestamp nullable' } + AuthUser: { id: id, username: string, password: string, last_login: timestamp, is_superuser: boolean, first_name: string, last_name: string, email: string, is_staff: boolean, is_active: boolean, date_joined: timestamp, timestamps: false } diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8f0de65 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[docker-compose.yml] +indent_size = 4 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..35db1dd --- /dev/null +++ b/.env.example @@ -0,0 +1,65 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_STORE=database + +PHP_CLI_SERVER_WORKERS=4 + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=sqlite +# DB_HOST=127.0.0.1 +# DB_PORT=3306 +# DB_DATABASE=laravel +# DB_USERNAME=root +# DB_PASSWORD= + +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +# CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +VITE_APP_NAME="${APP_NAME}" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fcb21d3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7cf1fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +/.phpunit.cache +/node_modules +/public/build +/public/hot +/public/storage +/storage/*.key +/storage/pail +/vendor +.env +.env.backup +.env.production +.phpactor.json +.phpunit.result.cache +Homestead.json +Homestead.yaml +npm-debug.log +yarn-error.log +/auth.json +/.fleet +/.idea +/.nova +/.vscode +/.zed diff --git a/README.md b/README.md new file mode 100644 index 0000000..1a4c26b --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +
+ + + +## About Laravel + +Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: + +- [Simple, fast routing engine](https://laravel.com/docs/routing). +- [Powerful dependency injection container](https://laravel.com/docs/container). +- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. +- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). +- Database agnostic [schema migrations](https://laravel.com/docs/migrations). +- [Robust background job processing](https://laravel.com/docs/queues). +- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). + +Laravel is accessible, powerful, and provides tools required for large, robust applications. + +## Learning Laravel + +Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. + +You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch. + +If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. + +## Laravel Sponsors + +We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com). + +### Premium Partners + +- **[Vehikl](https://vehikl.com/)** +- **[Tighten Co.](https://tighten.co)** +- **[WebReinvent](https://webreinvent.com/)** +- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** +- **[64 Robots](https://64robots.com)** +- **[Curotec](https://www.curotec.com/services/technologies/laravel/)** +- **[Cyber-Duck](https://cyber-duck.co.uk)** +- **[DevSquad](https://devsquad.com/hire-laravel-developers)** +- **[Jump24](https://jump24.co.uk)** +- **[Redberry](https://redberry.international/laravel/)** +- **[Active Logic](https://activelogic.com)** +- **[byte5](https://byte5.de)** +- **[OP.GG](https://op.gg)** + +## Contributing + +Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). + +## Code of Conduct + +In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). + +## Security Vulnerabilities + +If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. + +## License + +The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). diff --git a/app/Console/Commands/EnviarReporteVentas.php b/app/Console/Commands/EnviarReporteVentas.php new file mode 100644 index 0000000..f1a57e3 --- /dev/null +++ b/app/Console/Commands/EnviarReporteVentas.php @@ -0,0 +1,43 @@ +subWeek()->startOfWeek(); // Lunes anterior + $toDate = Carbon::now()->subWeek()->endOfWeek(); // Domingo anterior + + $ventas = Venta::with(['cliente', 'detalles.producto', 'detalles.variante']) + ->whereBetween('created_at', [$fromDate, $toDate]) + ->get(); + + // Obtener todos los usuarios con el rol 'Administrador' + $administradores = User::role('Administrador')->get(); + + if ($administradores->isEmpty()) { + $this->warn('No se encontraron usuarios con el rol Administrador.'); + return; + } + + foreach ($administradores as $admin) { + Mail::to($admin->email)->send(new ReporteVentasMail($ventas, $fromDate, $toDate, $admin->email)); + $this->info("Reporte enviado a: {$admin->email}"); + } + + $this->info('Todos los reportes han sido enviados a los administradores.'); + } +} \ No newline at end of file diff --git a/app/Console/Commands/MigrarStockBodegaPrincipal.php b/app/Console/Commands/MigrarStockBodegaPrincipal.php new file mode 100644 index 0000000..3a2a4b8 --- /dev/null +++ b/app/Console/Commands/MigrarStockBodegaPrincipal.php @@ -0,0 +1,115 @@ +info('Iniciando migración de stock a bodega principal...'); + + DB::beginTransaction(); + + try { + // 1. Crear o encontrar la bodega principal + $bodegaPrincipal = Bodega::firstOrCreate([ + 'nombre' => 'Principal' + ]); + + $this->info("Bodega principal creada/encontrada: {$bodegaPrincipal->nombre}"); + + // 2. Obtener todos los productos que necesitan migración + $productos = Producto::with('variants')->get()->filter(function ($producto) { + // Productos con stock directo O con variantes que tienen stock + return $producto->stock > 0 || + ($producto->variants()->exists() && $producto->variants()->sum('stock') > 0); + }); + + $this->info("Encontrados {$productos->count()} productos con stock para migrar"); + + $productosActualizados = 0; + + foreach ($productos as $producto) { + // Calcular stock total a migrar + $stockAMigrar = 0; + + if ($producto->variants()->exists()) { + // Para productos con variantes, usar la suma de variantes + $stockAMigrar = $producto->variants()->sum('stock'); + $this->line(" → Producto con variantes: {$producto->nombre}"); + $this->line(" Stock total de variantes: {$stockAMigrar}"); + } else { + // Para productos sin variantes, usar stock directo + $stockAMigrar = $producto->stock; + } + + if ($stockAMigrar <= 0) { + continue; // Saltar productos sin stock + } + // Verificar si ya existe una relación con esta bodega + $existeRelacion = $producto->bodegas() + ->where('bodega_id', $bodegaPrincipal->id) + ->exists(); + + if (!$existeRelacion) { + // Crear la relación con el stock calculado + $producto->bodegas()->attach($bodegaPrincipal->id, [ + 'stock' => $stockAMigrar + ]); + + $this->line("✓ {$producto->nombre}: {$stockAMigrar} unidades → Bodega Principal"); + $productosActualizados++; + } else { + // Actualizar el stock existente sumando el stock calculado + $stockActual = $producto->bodegas() + ->where('bodega_id', $bodegaPrincipal->id) + ->first()->pivot->stock; + + $nuevoStock = $stockActual + $stockAMigrar; + + $producto->bodegas()->updateExistingPivot($bodegaPrincipal->id, [ + 'stock' => $nuevoStock + ]); + + $this->line("✓ {$producto->nombre}: {$stockActual} + {$stockAMigrar} = {$nuevoStock} unidades → Bodega Principal"); + $productosActualizados++; + } + } + + DB::commit(); + + $this->info("\n🎉 Migración completada exitosamente!"); + $this->info("📦 Productos procesados: {$productosActualizados}"); + $this->info("🏢 Bodega principal: {$bodegaPrincipal->nombre}"); + + } catch (\Exception $e) { + DB::rollBack(); + $this->error("❌ Error durante la migración: " . $e->getMessage()); + return Command::FAILURE; + } + + return Command::SUCCESS; + } +} diff --git a/app/Console/Commands/MigrarVariantesBodegaPrincipal.php b/app/Console/Commands/MigrarVariantesBodegaPrincipal.php new file mode 100644 index 0000000..82d1c67 --- /dev/null +++ b/app/Console/Commands/MigrarVariantesBodegaPrincipal.php @@ -0,0 +1,144 @@ +info('🚀 Iniciando migración completa de stock a bodega principal...'); + + DB::beginTransaction(); + + try { + // 1. Crear o encontrar la bodega principal + $bodegaPrincipal = Bodega::firstOrCreate([ + 'nombre' => 'Principal' + ], [ + 'descripcion' => 'Bodega principal del sistema', + 'ubicacion' => 'Sede principal', + 'estado' => true + ]); + + $this->info("✅ Bodega principal: {$bodegaPrincipal->nombre}"); + + // 2. MIGRAR PRODUCTOS DIRECTOS (sin variantes) + $this->info("\n📦 Migrando productos directos..."); + $productosDirectos = Producto::where('estado', true) + ->where('stock', '>', 0) + ->whereDoesntHave('variants') // Solo productos sin variantes + ->get(); + + $this->info("Encontrados {$productosDirectos->count()} productos directos con stock"); + + $productosActualizados = 0; + + foreach ($productosDirectos as $producto) { + // Verificar si ya existe una relación con esta bodega + $existeRelacion = $producto->bodegas() + ->where('bodega_id', $bodegaPrincipal->id) + ->exists(); + + if (!$existeRelacion) { + // Crear la relación con el stock actual del producto + $producto->bodegas()->attach($bodegaPrincipal->id, [ + 'stock' => $producto->stock + ]); + + $this->line("✓ {$producto->nombre}: {$producto->stock} unidades → Bodega Principal"); + $productosActualizados++; + } else { + // Actualizar el stock existente + $stockActual = $producto->bodegas() + ->where('bodega_id', $bodegaPrincipal->id) + ->first()->pivot->stock; + + $nuevoStock = $stockActual + $producto->stock; + + $producto->bodegas()->updateExistingPivot($bodegaPrincipal->id, [ + 'stock' => $nuevoStock + ]); + + $this->line("✓ {$producto->nombre}: {$stockActual} + {$producto->stock} = {$nuevoStock} unidades → Bodega Principal"); + $productosActualizados++; + } + } + + // 3. MIGRAR VARIANTES DE PRODUCTOS + $this->info("\n🔄 Migrando variantes de productos..."); + $variantes = ProductVariant::with('producto') + ->where('stock', '>', 0) + ->get(); + + $this->info("Encontradas {$variantes->count()} variantes con stock"); + + $variantesActualizadas = 0; + + foreach ($variantes as $variante) { + // Verificar si ya existe una relación con esta bodega + $existeRelacion = $variante->bodegas() + ->where('bodega_id', $bodegaPrincipal->id) + ->exists(); + + if (!$existeRelacion) { + // Crear la relación con el stock actual de la variante + $variante->bodegas()->attach($bodegaPrincipal->id, [ + 'stock' => $variante->stock + ]); + + $this->line("✓ {$variante->producto->nombre} [{$variante->sku}]: {$variante->stock} unidades → Bodega Principal"); + $variantesActualizadas++; + } else { + // Actualizar el stock existente sumando el stock de la variante + $stockActual = $variante->bodegas() + ->where('bodega_id', $bodegaPrincipal->id) + ->first()->pivot->stock; + + $nuevoStock = $stockActual + $variante->stock; + + $variante->bodegas()->updateExistingPivot($bodegaPrincipal->id, [ + 'stock' => $nuevoStock + ]); + + $this->line("✓ {$variante->producto->nombre} [{$variante->sku}]: {$stockActual} + {$variante->stock} = {$nuevoStock} unidades → Bodega Principal"); + $variantesActualizadas++; + } + } + + DB::commit(); + + $this->info("\n🎉 Migración completa de stock exitosa!"); + $this->info("📦 Productos directos procesados: {$productosActualizados}"); + $this->info("� Variantes procesadas: {$variantesActualizadas}"); + $this->info("🏢 Bodega principal: {$bodegaPrincipal->nombre}"); + $this->info("📊 Total de elementos migrados: " . ($productosActualizados + $variantesActualizadas)); + + } catch (\Exception $e) { + DB::rollBack(); + $this->error("❌ Error durante la migración: " . $e->getMessage()); + $this->error("🔍 Línea: " . $e->getLine()); + return Command::FAILURE; + } + + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/app/Console/Commands/VerificarAlertasStock.php b/app/Console/Commands/VerificarAlertasStock.php new file mode 100644 index 0000000..d270f5d --- /dev/null +++ b/app/Console/Commands/VerificarAlertasStock.php @@ -0,0 +1,153 @@ +info('🔍 Iniciando verificación de niveles de stock...'); + + // Obtener productos con stock mínimo o inferior + $productosStockMinimo = $this->obtenerProductosStockMinimo(); + + // Obtener productos que exceden el stock máximo + $productosStockMaximo = $this->obtenerProductosStockMaximo(); + + if ($productosStockMinimo->isEmpty() && $productosStockMaximo->isEmpty()) { + $this->info('✅ Todos los productos están en niveles normales de stock.'); + return Command::SUCCESS; + } + + // Mostrar resumen en consola + $this->mostrarResumen($productosStockMinimo, $productosStockMaximo); + + // Enviar alertas por correo + $this->enviarAlertas($productosStockMinimo, $productosStockMaximo); + + return Command::SUCCESS; + } + + private function obtenerProductosStockMinimo() + { + return Producto::with(['categoria', 'variants', 'bodegas']) + ->where('estado', true) + ->get() + ->filter(function ($producto) { + // Usar el método getStockEfectivo que considera bodegas + $stockActual = $producto->getStockEfectivo(); + + return $stockActual <= $producto->stock_minimo; + }); + } + + private function obtenerProductosStockMaximo() + { + return Producto::with(['categoria', 'variants', 'bodegas']) + ->where('estado', true) + ->whereNotNull('stock_maximo') + ->get() + ->filter(function ($producto) { + // Usar el método getStockEfectivo que considera bodegas + $stockActual = $producto->getStockEfectivo(); + + return $stockActual > $producto->stock_maximo; + }); + } + + private function mostrarResumen($productosStockMinimo, $productosStockMaximo) + { + if ($productosStockMinimo->isNotEmpty()) { + $this->warn("⚠️ {$productosStockMinimo->count()} productos con stock mínimo o inferior:"); + + $headers = ['Producto', 'Stock Actual', 'Stock Mínimo', 'Estado']; + $rows = []; + + foreach ($productosStockMinimo as $producto) { + $stockActual = $producto->getStockEfectivo(); + + $estado = $stockActual == 0 ? 'Sin Stock' : ($stockActual < $producto->stock_minimo ? 'Por debajo' : 'En mínimo'); + + $rows[] = [ + $producto->nombre, + $stockActual, + $producto->stock_minimo, + $estado + ]; + } + + $this->table($headers, $rows); + } + + if ($productosStockMaximo->isNotEmpty()) { + $this->info("📈 {$productosStockMaximo->count()} productos que exceden el stock máximo:"); + + $headers = ['Producto', 'Stock Actual', 'Stock Máximo', 'Exceso']; + $rows = []; + + foreach ($productosStockMaximo as $producto) { + $stockActual = $producto->getStockEfectivo(); + + $exceso = $stockActual - $producto->stock_maximo; + + $rows[] = [ + $producto->nombre, + $stockActual, + $producto->stock_maximo, + "+{$exceso}" + ]; + } + + $this->table($headers, $rows); + } + } + + private function enviarAlertas($productosStockMinimo, $productosStockMaximo) + { + // Determinar destinatarios + $email = $this->option('email'); + + if ($email) { + $destinatarios = collect([$email]); + $this->info("📧 Enviando alerta a email específico: {$email}"); + } else { + // Obtener administradores + $administradores = User::role('Administrador')->get(); + + if ($administradores->isEmpty()) { + $this->warn('⚠️ No se encontraron usuarios con el rol Administrador.'); + return; + } + + $destinatarios = $administradores->pluck('email'); + $this->info("📧 Enviando alertas a {$administradores->count()} administradores..."); + } + + // Enviar correos + foreach ($destinatarios as $emailDestino) { + try { + Mail::to($emailDestino)->send(new AlertaStockMail( + $productosStockMinimo, + $productosStockMaximo, + $emailDestino + )); + + $this->info("✅ Alerta enviada a: {$emailDestino}"); + } catch (\Exception $e) { + $this->error("❌ Error al enviar a {$emailDestino}: " . $e->getMessage()); + } + } + + $this->info('🎉 Proceso de envío de alertas completado.'); + } +} \ No newline at end of file diff --git a/app/Exports/PlantillaCompraExport.php b/app/Exports/PlantillaCompraExport.php new file mode 100644 index 0000000..3f7b5a2 --- /dev/null +++ b/app/Exports/PlantillaCompraExport.php @@ -0,0 +1,106 @@ + [ + 'font' => [ + 'bold' => true, + 'size' => 12, + 'color' => ['rgb' => 'FFFFFF'], + ], + 'fill' => [ + 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, + 'startColor' => ['rgb' => '4472C4'], + ], + 'alignment' => [ + 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, + 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, + ], + ], + // Filas de datos + '2:8' => [ + 'alignment' => [ + 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER, + ], + ], + // Filas de instrucciones + '5:8' => [ + 'font' => [ + 'italic' => true, + 'color' => ['rgb' => '666666'], + ], + ], + ]; + } + + /** + * Ancho de las columnas + */ + public function columnWidths(): array + { + return [ + 'A' => 20, // Codigo de Barras + 'B' => 25, // Producto + 'C' => 12, // Cantidad + 'D' => 18, // Precio Unitario + 'E' => 15, // Bodega + 'F' => 35, // Observaciones + ]; + } + + /** + * Título de la hoja + */ + public function title(): string + { + return 'Plantilla Compras'; + } +} diff --git a/app/Exports/ProductosExport.php b/app/Exports/ProductosExport.php new file mode 100644 index 0000000..7054441 --- /dev/null +++ b/app/Exports/ProductosExport.php @@ -0,0 +1,184 @@ +get(); + } + + /** + * Define los encabezados del Excel + */ + public function headings(): array + { + return [ + 'ID', + 'Nombre', + 'Descripcion', + 'Codigo_de_Barras', + 'Categoria', + 'Precio_Compra', + 'Precio_Venta', + 'Stock', + 'Stock_Minimo', + 'Stock_Maximo', + 'Unidad_de_Medida', + 'Estado', + ]; + } + + /** + * Mapea cada producto a una fila del Excel + */ + public function map($producto): array + { + return [ + $producto->id, + $producto->nombre, + $producto->descripcion, + $producto->codigo_barras, + $producto->categoria?->nombre ?? '', + $producto->precio_compra, + $producto->precio_venta, + $producto->getStockEfectivo(), + $producto->stock_minimo, + $producto->stock_maximo, + $producto->unidad_medida ?? 'unidad', + $producto->estado ? 'Activo' : 'Inactivo', + ]; + } + + /** + * Aplica estilos al Excel + */ + public function styles(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet) + { + return [ + // Estilo para la fila de encabezados + 1 => [ + 'font' => ['bold' => true], + 'fill' => [ + 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, + 'startColor' => ['rgb' => '4F46E5'] + ], + 'font' => [ + 'bold' => true, + 'color' => ['rgb' => 'FFFFFF'] + ] + ], + ]; + } + + /** + * Título de la hoja + */ + public function title(): string + { + return 'Productos'; + } +} + +/** + * Hoja de referencia de categorías + */ +class CategoriasReferenciaSheet implements + \Maatwebsite\Excel\Concerns\FromCollection, + \Maatwebsite\Excel\Concerns\WithHeadings, + \Maatwebsite\Excel\Concerns\WithMapping, + \Maatwebsite\Excel\Concerns\WithStyles, + \Maatwebsite\Excel\Concerns\ShouldAutoSize, + \Maatwebsite\Excel\Concerns\WithTitle +{ + /** + * Retorna la colección de categorías + */ + public function collection() + { + return Categoria::all(); + } + + /** + * Define los encabezados + */ + public function headings(): array + { + return [ + 'ID', + 'Nombre_de_Categoria', + 'Descripcion', + ]; + } + + /** + * Mapea cada categoría a una fila + */ + public function map($categoria): array + { + return [ + $categoria->id, + $categoria->nombre, + 'Usa este nombre en la columna "Categoria" de la hoja Productos', + ]; + } + + /** + * Aplica estilos + */ + public function styles(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet) + { + return [ + 1 => [ + 'font' => ['bold' => true], + 'fill' => [ + 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, + 'startColor' => ['rgb' => '10B981'] + ], + 'font' => [ + 'bold' => true, + 'color' => ['rgb' => 'FFFFFF'] + ] + ], + ]; + } + + /** + * Título de la hoja + */ + public function title(): string + { + return 'Categorías Disponibles'; + } +} diff --git a/app/Filament/Pages/GestionStockPage.php b/app/Filament/Pages/GestionStockPage.php new file mode 100644 index 0000000..ae86bbf --- /dev/null +++ b/app/Filament/Pages/GestionStockPage.php @@ -0,0 +1,153 @@ +productosStockBajo = $this->getProductosStockBajo(); + $this->bodegasEstado = $this->getBodegasEstado(); + $this->sugerenciasTransferencia = $this->getSugerenciasTransferencia(); + } + + protected function getProductosStockBajo() + { + return Producto::with(['bodegas', 'categoria']) + ->where('estado', true) + ->get() + ->filter(function ($producto) { + return $producto->getStockEfectivo() <= $producto->stock_minimo; + }) + ->map(function ($producto) { + return [ + 'id' => $producto->id, + 'nombre' => $producto->nombre, + 'categoria' => $producto->categoria->nombre ?? 'Sin categoría', + 'stock_actual' => $producto->getStockEfectivo(), + 'stock_minimo' => $producto->stock_minimo, + 'distribucion' => $producto->bodegas->map(function ($bodega) { + return [ + 'bodega' => $bodega->nombre, + 'stock' => $bodega->pivot->stock, + ]; + })->toArray(), + ]; + }) + ->toArray(); + } + + protected function getBodegasEstado() + { + return Bodega::with('productos') + ->get() + ->map(function ($bodega) { + $totalProductos = $bodega->productos()->count(); + $productosConStock = $bodega->productos()->wherePivot('stock', '>', 0)->count(); + $stockTotal = $bodega->productos()->sum('producto_bodega.stock'); + + return [ + 'id' => $bodega->id, + 'nombre' => $bodega->nombre, + 'total_productos' => $totalProductos, + 'productos_con_stock' => $productosConStock, + 'stock_total' => $stockTotal, + 'utilizacion' => $totalProductos > 0 ? round(($productosConStock / $totalProductos) * 100, 1) : 0, + ]; + }) + ->toArray(); + } + + protected function getSugerenciasTransferencia() + { + $sugerencias = []; + + // Buscar productos con stock desbalanceado entre bodegas + $productos = Producto::with('bodegas') + ->where('estado', true) + ->get(); + + foreach ($productos as $producto) { + if ($producto->bodegas->count() > 1) { + $bodegas = $producto->bodegas->sortByDesc('pivot.stock'); + $mayor = $bodegas->first(); + $menor = $bodegas->last(); + + // Si hay gran diferencia de stock entre bodegas + if ($mayor->pivot->stock > 0 && $menor->pivot->stock <= $producto->stock_minimo) { + $cantidadSugerida = min( + floor($mayor->pivot->stock * 0.3), // Máximo 30% del stock de la bodega con más stock + $producto->stock_minimo - $menor->pivot->stock + 5 // Lo necesario para estar sobre el mínimo + ); + + if ($cantidadSugerida > 0) { + $sugerencias[] = [ + 'producto_id' => $producto->id, + 'producto_nombre' => $producto->nombre, + 'bodega_origen' => $mayor->nombre, + 'bodega_origen_id' => $mayor->id, + 'bodega_destino' => $menor->nombre, + 'bodega_destino_id' => $menor->id, + 'cantidad_sugerida' => $cantidadSugerida, + 'razon' => "Rebalanceo: {$menor->nombre} bajo mínimo", + 'stock_origen' => $mayor->pivot->stock, + 'stock_destino' => $menor->pivot->stock, + ]; + } + } + } + } + + return collect($sugerencias)->take(10)->toArray(); + } + + public function ejecutarTransferenciaSugerida($data) + { + try { + $service = new TransferenciaBodegaService(); + + $transferencia = $service->transferir( + $data['producto_id'], + $data['bodega_origen_id'], + $data['bodega_destino_id'], + $data['cantidad_sugerida'], + $data['razon'] . ' (Transferencia automática sugerida)' + ); + + Notification::make() + ->title('Transferencia ejecutada') + ->body("Se transfirieron {$data['cantidad_sugerida']} unidades de {$data['producto_nombre']}") + ->success() + ->send(); + + // Recargar datos + $this->mount(); + + } catch (\Exception $e) { + Notification::make() + ->title('Error en transferencia') + ->body($e->getMessage()) + ->danger() + ->send(); + } + } +} \ No newline at end of file diff --git a/app/Filament/Pages/PuntoVenta.php b/app/Filament/Pages/PuntoVenta.php new file mode 100644 index 0000000..765d601 --- /dev/null +++ b/app/Filament/Pages/PuntoVenta.php @@ -0,0 +1,480 @@ + null, + 'correo' => null, + 'telefono' => null, + ]; + public $cliente_id = null; + + public $correoCotizacion = ''; + public $bodega_id = null; // Bodega seleccionada para la venta + + public function mount() + { + $this->productos = Producto::where('estado', true) + ->where(function ($query) { + $query->where('stock', '>', 0) + ->orWhereHas('bodegas', function ($q) { + $q->where('producto_bodega.stock', '>', 0); + }) + ->orWhereHas('variants', function ($q) { + $q->where('stock', '>', 0) + ->orWhereHas('bodegas', function ($bq) { + $bq->where('variante_bodega.stock', '>', 0); + }); + }); + }) + ->with('variants.color', 'variants.size', 'bodegas') + ->limit(20) + ->get(); + + // Seleccionar bodega "Principal" por defecto + $bodegaPrincipal = \App\Models\Bodega::where('nombre', 'Principal')->first(); + $this->bodega_id = $bodegaPrincipal ? $bodegaPrincipal->id : null; + } + + public function agregarAlCarrito($productoId, $tipo) + { + if ($tipo == 'p') { + $producto = Producto::find($productoId); + if (!$producto) + return; + + $key = 'p-' . $producto->id; + + if (!isset($this->carrito[$key])) { + $this->carrito[$key] = [ + 'id' => $producto->id, + 'nombre' => $producto->nombre, + 'precio_venta' => $producto->precio_venta, + 'precio_original' => $producto->precio_venta, + 'precio_modificado' => $producto->precio_venta, + 'cantidad' => 1, + 'tipo' => 'p', + ]; + } else { + $this->carrito[$key]['cantidad']++; + } + } else { + $producto = ProductVariant::find($productoId); + if (!$producto) + return; + + $key = 'v-' . $producto->id; + + if (!isset($this->carrito[$key])) { + $this->carrito[$key] = [ + 'id' => $producto->producto->id, + 'nombre' => $producto->producto->nombre, + 'precio_venta' => $producto->producto->precio_venta, + 'precio_original' => $producto->producto->precio_venta, + 'precio_modificado' => $producto->producto->precio_venta, + 'variante' => 'Color: ' . $producto->color->name . ', Talla: ' . $producto->size->name, + 'variante_id' => $producto->id, + 'cantidad' => 1, + 'tipo' => 'v', + ]; + } else { + $this->carrito[$key]['cantidad']++; + } + } + + $this->calcularTotal(); + } + + + public function calcularTotal() + { + $this->total = collect($this->carrito)->sum(fn($item) => $item['precio_modificado'] * $item['cantidad']); + } + + public function actualizarPrecio($key, $nuevoPrecio) + { + if (isset($this->carrito[$key])) { + // Validar que el precio sea válido (mayor o igual a 0) + $precio = floatval($nuevoPrecio); + if ($precio >= 0) { + $this->carrito[$key]['precio_modificado'] = $precio; + $this->calcularTotal(); + } + } + } + + public function procesarVenta() + { + if (empty($this->carrito)) { + session()->flash('error', 'No se puede procesar la venta: el carrito está vacío.'); + return; + } + + DB::beginTransaction(); + try { + $clienteId = null; + + if ($this->numeroDocumentoCliente) { + $cliente = Cliente::where('numero_documento', $this->numeroDocumentoCliente)->first(); + + if (!$cliente) { + $datosCliente = [ + 'nombre' => $this->datosCliente['nombre'] ?? "Cliente General", + 'correo' => $this->datosCliente['correo'] ?? null, + 'telefono' => $this->datosCliente['telefono'] ?? null, + 'numero_documento' => $this->numeroDocumentoCliente, + 'tipo_documento' => $this->datosCliente['tipo_documento'] ?? 'CC', + ]; + + $cliente = Cliente::create($datosCliente); + } + + $clienteId = $cliente->id; + } elseif ($this->cliente_id) { + $cliente = Cliente::find($this->cliente_id); + if ($cliente) { + $clienteId = $cliente->id; + } else { + $this->cliente_id = null; + $clienteId = null; + } + } + + $venta = Venta::create([ + 'cliente_id' => $clienteId, + 'total' => $this->total, + 'tipo_pago' => $this->tipo_pago, + 'estado' => 'Pagado', + ]); + + foreach ($this->carrito as $item) { + $precioOriginal = $item['precio_original']; + $precioModificado = $item['precio_modificado']; + $descuentoAplicado = $precioOriginal - $precioModificado; + $cantidadPendiente = $item['cantidad']; + + // Identificar el producto o variante real + $producto = null; + $variante = null; + + if (isset($item['variante_id'])) { + $variante = ProductVariant::find($item['variante_id']); + $producto = $variante->producto; + } else { + $producto = Producto::find($item['id']); + } + + // Estrategia de deducción de stock: + // 1. Buscar en Bodega Principal + // 2. Buscar en otras bodegas con stock + // 3. Si falta, descontar de stock directo (o dejar negativo en Principal si se prefiere, aquí usaremos Principal como fallback) + + $bodegas = \App\Models\Bodega::orderByRaw("CASE WHEN nombre = 'Principal' THEN 0 ELSE 1 END")->get(); + + foreach ($bodegas as $bodega) { + if ($cantidadPendiente <= 0) break; + + $stockDisponible = 0; + + if ($variante) { + $bodegaVariante = $variante->bodegas()->where('bodega_id', $bodega->id)->first(); + $stockDisponible = $bodegaVariante ? $bodegaVariante->pivot->stock : 0; + } else { + $bodegaProducto = $producto->bodegas()->where('bodega_id', $bodega->id)->first(); + $stockDisponible = $bodegaProducto ? $bodegaProducto->pivot->stock : 0; + } + + if ($stockDisponible > 0) { + $cantidadADescontar = min($cantidadPendiente, $stockDisponible); + + // Registrar detalle para esta bodega + $venta->detalles()->create([ + 'producto_id' => $item['id'], + 'variante_id' => $item['variante_id'] ?? null, + 'bodega_id' => $bodega->id, + 'cantidad' => $cantidadADescontar, + 'precio_unitario' => $precioModificado, + 'precio_original' => $precioOriginal, + 'descuento_aplicado' => $descuentoAplicado, + 'usuario_modifico_precio_id' => ($descuentoAplicado != 0) ? auth()->id() : null, + 'subtotal' => $cantidadADescontar * $precioModificado, + ]); + + // Actualizar stock + if ($variante) { + $variante->bodegas()->updateExistingPivot($bodega->id, [ + 'stock' => $stockDisponible - $cantidadADescontar + ]); + } else { + $producto->bodegas()->updateExistingPivot($bodega->id, [ + 'stock' => $stockDisponible - $cantidadADescontar + ]); + } + + $cantidadPendiente -= $cantidadADescontar; + } + } + + // Si aún queda cantidad pendiente (no había stock suficiente en ninguna bodega) + // Lo asignamos a la Bodega Principal (o NULL si no hay bodegas) y dejamos que el stock se vaya a negativo o se descuente del directo + if ($cantidadPendiente > 0) { + $bodegaFallback = $bodegas->first(); // Principal por el ordenamiento + $bodegaIdFallback = $bodegaFallback ? $bodegaFallback->id : null; + + $venta->detalles()->create([ + 'producto_id' => $item['id'], + 'variante_id' => $item['variante_id'] ?? null, + 'bodega_id' => $bodegaIdFallback, + 'cantidad' => $cantidadPendiente, + 'precio_unitario' => $precioModificado, + 'precio_original' => $precioOriginal, + 'descuento_aplicado' => $descuentoAplicado, + 'usuario_modifico_precio_id' => ($descuentoAplicado != 0) ? auth()->id() : null, + 'subtotal' => $cantidadPendiente * $precioModificado, + ]); + + // Intentar descontar del fallback + if ($bodegaFallback) { + if ($variante) { + $bodegaVariante = $variante->bodegas()->where('bodega_id', $bodegaFallback->id)->first(); + if ($bodegaVariante) { + $variante->bodegas()->updateExistingPivot($bodegaFallback->id, [ + 'stock' => $bodegaVariante->pivot->stock - $cantidadPendiente + ]); + } else { + // Si no existe la relación, la creamos con stock negativo + $variante->bodegas()->attach($bodegaFallback->id, ['stock' => -$cantidadPendiente]); + } + } else { + $bodegaProducto = $producto->bodegas()->where('bodega_id', $bodegaFallback->id)->first(); + if ($bodegaProducto) { + $producto->bodegas()->updateExistingPivot($bodegaFallback->id, [ + 'stock' => $bodegaProducto->pivot->stock - $cantidadPendiente + ]); + } else { + $producto->bodegas()->attach($bodegaFallback->id, ['stock' => -$cantidadPendiente]); + } + } + } else { + // Si no hay bodegas en absoluto, descontar del stock directo + if ($variante) { + $variante->decrement('stock', $cantidadPendiente); + } else { + $producto->decrement('stock', $cantidadPendiente); + } + } + } + } + + $cajaAbierta = Caja::where('estado', 'Abierta') + ->orderBy('fecha_apertura', 'desc') + ->first(); + + if ($cajaAbierta) { + MovimientoCaja::create([ + 'caja_id' => $cajaAbierta->id, + 'tipo' => 'Ingreso', + 'monto' => $this->total, + 'descripcion' => 'Venta realizada. Venta ID: ' . $venta->id, + ]); + } + + DB::commit(); + + $this->resetVentaState(); + + session()->flash('message', 'Venta realizada con éxito.'); + $this->js("window.dispatchEvent(new CustomEvent('imprimir-recibo', { detail: { venta_id: {$venta->id} } }));"); + + } catch (\Exception $e) { + DB::rollBack(); + $this->resetVentaState(); + session()->flash('error', 'Error al procesar la venta. ' . $e->getMessage()); + } + } + + /** + * Resetea el estado de la venta para evitar inconsistencias + */ + private function resetVentaState() + { + $this->carrito = []; + $this->total = 0; + $this->numeroDocumentoCliente = ''; + $this->datosCliente = [ + 'nombre' => null, + 'correo' => null, + 'telefono' => null, + ]; + $this->cliente_id = null; + $this->tipo_pago = 'Efectivo'; + + // Mantener la bodega seleccionada para la próxima venta + // $this->bodega_id se mantiene + } + + + + + public function buscarProductoPorBarcode() + { + $barcode = trim($this->barcodeBusqueda); + + $producto = Producto::where('codigo_barras', $barcode)->first(); + $tipo = 'p'; + + + if (!$producto) { + $producto = ProductVariant::where('barcode', $barcode)->first(); + $tipo = 'v'; + } + + if ($producto) { + $this->agregarAlCarrito($producto->id, $tipo); + $this->barcodeBusqueda = ''; + } else { + session()->flash('error', 'Producto no encontrado.'); + } + } + + public function incrementarCantidad($key) + { + if (isset($this->carrito[$key])) { + $this->carrito[$key]['cantidad']++; + $this->calcularTotal(); + } + } + + public function decrementarCantidad($key) + { + if (isset($this->carrito[$key])) { + $this->carrito[$key]['cantidad']--; + + if ($this->carrito[$key]['cantidad'] <= 0) { + unset($this->carrito[$key]); + } + + $this->calcularTotal(); + } + } + + public function eliminarDelCarrito($key) + { + if (isset($this->carrito[$key])) { + unset($this->carrito[$key]); + $this->calcularTotal(); + } + } + public function enviarCotizacion() + { + $correo = $this->correoCotizacion; + + if (!filter_var($correo, FILTER_VALIDATE_EMAIL)) { + session()->flash('error', 'Correo inválido.'); + return; + } + + try { + $carrito = $this->carrito; + $total = $this->total; + + Mail::send('emails.cotizacion', compact('carrito', 'total'), function ($message) use ($correo) { + $message->to($correo) + ->subject('Cotización de productos'); + }); + + session()->flash('message', 'Cotización enviada exitosamente.'); + $this->correoCotizacion = ''; + } catch (\Exception $e) { + session()->flash('error', 'Error al enviar la cotización: ' . $e->getMessage()); + } + } + + public function buscarClientePorDocumento() + { + $documento = trim($this->numeroDocumentoCliente); + + if (!$documento) { + // No se requiere documento + $this->cliente_id = null; + $this->datosCliente = [ + 'nombre' => null, + 'correo' => null, + 'telefono' => null, + ]; + return; + } + + $cliente = Cliente::where('numero_documento', $documento)->first(); + + if ($cliente) { + // Verificar que el cliente encontrado existe realmente + $clienteValidado = Cliente::find($cliente->id); + if ($clienteValidado) { + $this->cliente_id = $clienteValidado->id; + $this->datosCliente = [ + 'nombre' => $clienteValidado->nombre, + 'correo' => $clienteValidado->correo, + 'telefono' => $clienteValidado->telefono, + ]; + } else { + // Cliente no válido, resetear + $this->cliente_id = null; + $this->datosCliente = [ + 'nombre' => null, + 'correo' => null, + 'telefono' => null, + ]; + } + } else { + $this->cliente_id = null; + $this->datosCliente = [ + 'nombre' => null, + 'correo' => null, + 'telefono' => null, + ]; + } + } + + public function cambiarBodega($bodegaId) + { + $this->bodega_id = $bodegaId; + + // Opcional: mostrar notificación de cambio + session()->flash('message', 'Bodega cambiada. Las ventas se realizarán desde la nueva bodega seleccionada.'); + } + + public function getBodegasProperty() + { + return \App\Models\Bodega::all(); + } + + +} diff --git a/app/Filament/Pages/SettingPage.php b/app/Filament/Pages/SettingPage.php new file mode 100644 index 0000000..70f256e --- /dev/null +++ b/app/Filament/Pages/SettingPage.php @@ -0,0 +1,133 @@ +form->fill($setting?->toArray() ?? [ + 'logo' => null, + 'description' => null, + 'primary_color' => '#3498db', + 'secondary_color' => '#2ecc71', + ]); + } + + protected function getFormSchema(): array + { + return [ + FileUpload::make('logo') + ->image() + ->label('Logo') + ->directory('settings/logos') + ->required(), + + Textarea::make('description') + ->label('Descripción') + ->maxLength(500) + ->required(), + + ColorPicker::make('primary_color') + ->label('Color Primario') + ->required(), + + ColorPicker::make('secondary_color') + ->label('Color Secundario') + ->required(), + ]; + } + + public function save() + { + $data = $this->form->getState(); + + Setting::updateOrCreate(['id' => 1], $data); + + // Enviar notificación de éxito + Notification::make() + ->title('Éxito') + ->body('Configuraciones guardadas exitosamente.') + ->success() + ->send(); + + //$this->notify('success', 'Configuraciones guardadas exitosamente.'); + } + + protected function makeForm(): Form + { + return Form::make($this) + ->schema($this->getFormSchema()) + ->statePath('data'); + } + + + protected function getHeaderActions(): array + { + return [ + Actions\Action::make('Cerrar todas las sesiones') + ->color('danger') + ->requiresConfirmation() + ->action(function () { + if (config('session.driver') === 'file') { + // Eliminar todos los archivos de sesión + $files = File::files(storage_path('framework/sessions')); + foreach ($files as $file) { + File::delete($file); + } + } elseif (config('session.driver') === 'database') { + DB::table('sessions')->truncate(); + } + // Limpia tu propia sesión para desconectarte también + Session::flush(); + + + + Notification::make() + ->title('Sesiones cerradas') + ->body('Todas las sesiones han sido cerradas exitosamente.') + ->success() + ->send(); + }), + ]; + } + + +} diff --git a/app/Filament/Resources/BodegaResource.php b/app/Filament/Resources/BodegaResource.php new file mode 100644 index 0000000..3843bff --- /dev/null +++ b/app/Filament/Resources/BodegaResource.php @@ -0,0 +1,112 @@ +schema([ + TextInput::make('nombre') + ->required() + ->maxLength(255), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('id')->sortable(), + Tables\Columns\TextColumn::make('nombre')->searchable(), + Tables\Columns\TextColumn::make('stock_total') + ->label('Stock total') + ->getStateUsing(fn (Bodega $record) => $record->stock_total), + ]) + ->filters([ + // Puedes añadir filtros aquí si lo deseas + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make() + ->before(function (Bodega $record, Tables\Actions\DeleteAction $action) { + $hasStockProductos = $record->productos()->wherePivot('stock', '>', 0)->exists(); + $hasStockVariantes = $record->variantes()->wherePivot('stock', '>', 0)->exists(); + + if ($hasStockProductos || $hasStockVariantes) { + Notification::make() + ->warning() + ->title('No se puede eliminar') + ->body('Esta bodega tiene productos con stock asignado. Debe vaciar el stock antes de eliminarla.') + ->persistent() + ->send(); + + $action->cancel(); + } + }), + ]) + ->bulkActions([ + Tables\Actions\DeleteBulkAction::make() + ->action(function (Tables\Actions\DeleteBulkAction $action, \Illuminate\Database\Eloquent\Collection $records) { + foreach ($records as $record) { + $hasStockProductos = $record->productos()->wherePivot('stock', '>', 0)->exists(); + $hasStockVariantes = $record->variantes()->wherePivot('stock', '>', 0)->exists(); + + if ($hasStockProductos || $hasStockVariantes) { + Notification::make() + ->warning() + ->title('No se puede eliminar') + ->body("La bodega '{$record->nombre}' tiene productos con stock asignado. No se eliminó ninguna bodega.") + ->persistent() + ->send(); + + $action->cancel(); + return; + } + } + + $records->each->delete(); + + Notification::make() + ->success() + ->title('Bodegas eliminadas') + ->body('Las bodegas seleccionadas han sido eliminadas.') + ->send(); + }), + ]); + } + + public static function getRelations(): array + { + return [ + RelationManagers\ProductosRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListBodegas::route('/'), + 'create' => Pages\CreateBodega::route('/create'), + 'edit' => Pages\EditBodega::route('/{record}/edit'), + ]; + } +} +?> diff --git a/app/Filament/Resources/BodegaResource/Pages/CreateBodega.php b/app/Filament/Resources/BodegaResource/Pages/CreateBodega.php new file mode 100644 index 0000000..e6e3b17 --- /dev/null +++ b/app/Filament/Resources/BodegaResource/Pages/CreateBodega.php @@ -0,0 +1,16 @@ +getResource()::getUrl('index'); + } +} \ No newline at end of file diff --git a/app/Filament/Resources/BodegaResource/Pages/EditBodega.php b/app/Filament/Resources/BodegaResource/Pages/EditBodega.php new file mode 100644 index 0000000..965f0af --- /dev/null +++ b/app/Filament/Resources/BodegaResource/Pages/EditBodega.php @@ -0,0 +1,25 @@ +getResource()::getUrl('index'); + } +} \ No newline at end of file diff --git a/app/Filament/Resources/BodegaResource/Pages/ListBodegas.php b/app/Filament/Resources/BodegaResource/Pages/ListBodegas.php new file mode 100644 index 0000000..1fb5e9d --- /dev/null +++ b/app/Filament/Resources/BodegaResource/Pages/ListBodegas.php @@ -0,0 +1,19 @@ + \ No newline at end of file diff --git a/app/Filament/Resources/BodegaResource/Pages/ViewBodega.php b/app/Filament/Resources/BodegaResource/Pages/ViewBodega.php new file mode 100644 index 0000000..646829d --- /dev/null +++ b/app/Filament/Resources/BodegaResource/Pages/ViewBodega.php @@ -0,0 +1,19 @@ +columns([ + Tables\Columns\TextColumn::make('id') + ->label('ID') + ->sortable(), + + Tables\Columns\TextColumn::make('nombre') + ->searchable() + ->limit(50), + + Tables\Columns\TextColumn::make('precio_venta') + ->label('Precio venta') + ->money('USD', true), + + // Stock proviene del pivot (producto_bodega.stock) + Tables\Columns\TextColumn::make('pivot.stock') + ->label('Stock') + ->sortable(), + ]) + ->filters([ + // Puedes añadir filtros aquí si lo deseas + ]) + ->headerActions([ + // Si deseas crear productos desde aquí, descomenta: + // Tables\Actions\CreateAction::make(), + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]) + ->bulkActions([ + Tables\Actions\DeleteBulkAction::make(), + ]); + } +} +?> diff --git a/app/Filament/Resources/CajaResource.php b/app/Filament/Resources/CajaResource.php new file mode 100644 index 0000000..2dfc5e9 --- /dev/null +++ b/app/Filament/Resources/CajaResource.php @@ -0,0 +1,141 @@ +user()->can('ver caja'); + } + + public static function form(Form $form): Form + { + return $form + ->schema([ + TextInput::make('monto_inicial') + ->required() + ->numeric(), + TextInput::make('monto_final') + ->disabled(), // Deshabilitar para cálculo automático + Forms\Components\DateTimePicker::make('fecha_apertura') + ->required(), + Forms\Components\DateTimePicker::make('fecha_cierre'), + Select::make('estado') + ->label('Estado') + ->required() + ->options([ + 'Abierta' => 'Abierta', + 'Cerrada' => 'Cerrada', + ]) + ->afterStateUpdated(function (callable $set, $state, $get) { + // Si el estado se cambia a 'Cerrada', actualizamos la fecha de cierre y calculamos el monto final + if ($state === 'Cerrada') { + // Actualizamos la fecha de cierre al momento actual + $set('fecha_cierre', now()); + + // Obtener el ID del registro actual desde el contexto + $cajaId = $get('id'); // Usamos $get para obtener el ID del registro + + // Buscar la caja por su ID + $caja = Caja::find($cajaId); // Encontrar la caja por ID + + if ($caja) { + // Calcular monto final de acuerdo a los movimientos de caja + $montoFinal = $caja->calcularMontoFinal(); + + // Guardar el monto final calculado + $caja->update([ + 'monto_final' => $montoFinal, // Actualizamos el monto final en la base de datos + ]); + + // Ahora, actualizamos el estado del formulario + $set('monto_final', $montoFinal); // Actualizar el estado del formulario + } + } + }), + + + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('monto_inicial') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('monto_final') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('fecha_apertura') + ->dateTime() + ->sortable(), + Tables\Columns\TextColumn::make('fecha_cierre') + ->dateTime() + ->sortable(), + Tables\Columns\TextColumn::make('estado'), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // Filtros adicionales, si los necesitas + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + DetallesRelationManagerRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListCajas::route('/'), + 'create' => Pages\CreateCaja::route('/create'), + 'edit' => Pages\EditCaja::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/CajaResource/Pages/CreateCaja.php b/app/Filament/Resources/CajaResource/Pages/CreateCaja.php new file mode 100644 index 0000000..315395e --- /dev/null +++ b/app/Filament/Resources/CajaResource/Pages/CreateCaja.php @@ -0,0 +1,12 @@ +schema([ + Forms\Components\Select::make('tipo') + ->required() + ->options([ + 'Ingreso' => 'Ingreso', + 'Egreso' => 'Egreso', + ]) + ->placeholder('Selecciona un tipo'), + Forms\Components\TextInput::make('monto') + ->numeric() + ->required(), + Forms\Components\TextInput::make('descripcion') + ->maxLength(255), + ]); + } + + public function table(Table $table): Table + { + return $table->columns([ + Tables\Columns\TextColumn::make('tipo') + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('monto') + ->sortable() + ->numeric(), + Tables\Columns\TextColumn::make('descripcion'), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable(), + ]) + ->filters([ + // Aquí puedes agregar filtros si es necesario. + ]) + ->headerActions([ + Tables\Actions\CreateAction::make(), + ]); + } +} diff --git a/app/Filament/Resources/CategoriaResource.php b/app/Filament/Resources/CategoriaResource.php new file mode 100644 index 0000000..b92daaf --- /dev/null +++ b/app/Filament/Resources/CategoriaResource.php @@ -0,0 +1,87 @@ +user()->can('ver categoria'); + } + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('nombre') + ->required() + ->maxLength(255), + Forms\Components\Textarea::make('descripcion') + ->columnSpanFull(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('nombre') + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListCategorias::route('/'), + 'create' => Pages\CreateCategoria::route('/create'), + 'edit' => Pages\EditCategoria::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/CategoriaResource/Pages/CreateCategoria.php b/app/Filament/Resources/CategoriaResource/Pages/CreateCategoria.php new file mode 100644 index 0000000..98caab2 --- /dev/null +++ b/app/Filament/Resources/CategoriaResource/Pages/CreateCategoria.php @@ -0,0 +1,12 @@ +user()->can('ver clientes'); + } + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('nombre') + ->required() + ->maxLength(255), + Forms\Components\TextInput::make('correo') + ->maxLength(255), + Forms\Components\TextInput::make('telefono') + ->tel() + ->maxLength(20), + Forms\Components\TextInput::make('numero_documento') + ->required() + ->maxLength(20), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('nombre') + ->searchable(), + Tables\Columns\TextColumn::make('correo') + ->searchable(), + Tables\Columns\TextColumn::make('telefono') + ->searchable(), + Tables\Columns\TextColumn::make('numero_documento') + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListClientes::route('/'), + 'create' => Pages\CreateCliente::route('/create'), + 'edit' => Pages\EditCliente::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/ClienteResource/Pages/CreateCliente.php b/app/Filament/Resources/ClienteResource/Pages/CreateCliente.php new file mode 100644 index 0000000..6b9f31c --- /dev/null +++ b/app/Filament/Resources/ClienteResource/Pages/CreateCliente.php @@ -0,0 +1,12 @@ +user()->can('ver colores'); + } + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('name') + ->required() + ->maxLength(50), + ColorPicker::make('hex_code') + ->required(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('name') + ->searchable(), + ColorColumn::make('hex_code') + ->copyable() // Permite copiar el código HEX + ->sortable(), // Permite ordenar por color + + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListColors::route('/'), + 'create' => Pages\CreateColor::route('/create'), + 'edit' => Pages\EditColor::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/ColorResource/Pages/CreateColor.php b/app/Filament/Resources/ColorResource/Pages/CreateColor.php new file mode 100644 index 0000000..69e1a5e --- /dev/null +++ b/app/Filament/Resources/ColorResource/Pages/CreateColor.php @@ -0,0 +1,12 @@ +user()->can('ver compras'); + } + + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\Section::make('Información de la Compra') + ->schema([ + Forms\Components\Select::make('proveedor_id') + ->relationship('proveedor', 'nombre') + ->required() + ->columnSpan(1) + ->helperText('Selecciona el proveedor de esta compra'), + + Forms\Components\Select::make('estado') + ->required() + ->columnSpan(1) + ->options(function (Get $get) { + // Solo permite 'Pendiente' si no hay ID (creación) + return request()->routeIs('filament.admin.resources.compras.create') + ? ['Pendiente' => 'Pendiente'] + : [ + 'Pendiente' => 'Pendiente', + 'Recibida' => 'Recibida', + 'Anulada' => 'Anulada', + ]; + }) + ->default('Pendiente') + ->disabled(fn () => request()->routeIs('filament.admin.resources.compras.create')) + ->helperText(function (Get $get) { + return request()->routeIs('filament.admin.resources.compras.create') + ? 'Las compras se crean en estado "Pendiente"' + : 'Cambiar a "Recibida" actualizará automáticamente el stock en las bodegas'; + }), + + Forms\Components\Placeholder::make('total_display') + ->label('Total de la Compra') + ->columnSpan(2) + ->content(function (Get $get) { + $detalles = $get('detalles') ?? []; + $total = collect($detalles)->sum('subtotal'); + return '$' . number_format($total, 2); + }), + ]) + ->columns(2), + + Forms\Components\Section::make('Detalles de la Compra') + ->description('Agrega los productos de esta compra de forma rápida') + ->schema([ + Forms\Components\Repeater::make('detalles') + ->relationship('detalles') + ->schema([ + Forms\Components\TextInput::make('codigo_escaneado') + ->label('Código de barras') + ->placeholder('Escanea o escribe...') + ->live(onBlur: true) + ->columnSpan(2) + ->afterStateUpdated(function (Set $set, $state) { + if (!$state) return; + + // Buscar en ProductVariant + $variant = ProductVariant::where('barcode', $state)->first(); + if ($variant) { + $set('producto_id', $variant->producto_id); + $set('variante_id', $variant->id); + + $colorName = $variant->color ? $variant->color->name : 'Sin color'; + $sizeName = $variant->size ? $variant->size->name : 'Sin talla'; + + Notification::make() + ->success() + ->title('✓ Variante encontrada') + ->body("{$variant->producto->nombre} - {$colorName}/{$sizeName}") + ->send(); + return; + } + + // Buscar en Producto + $producto = Producto::where('codigo_barras', $state)->first(); + if ($producto) { + $set('producto_id', $producto->id); + $set('variante_id', null); + + if ($producto->variants()->exists()) { + Notification::make() + ->warning() + ->title('⚠ Producto con variantes') + ->body('Selecciona una variante específica.') + ->send(); + } else { + Notification::make() + ->success() + ->title('✓ Producto encontrado') + ->body($producto->nombre) + ->send(); + } + } else { + Notification::make() + ->warning() + ->title('Código no encontrado') + ->body('No existe un producto con este código.') + ->send(); + } + }), + + Forms\Components\Select::make('bodega_id') + ->label('Bodega') + ->relationship('bodega', 'nombre') + ->searchable() + ->required() + ->columnSpan(1) + ->default(function () { + $bodegaPrincipal = Bodega::where('nombre', 'Principal')->first(); + return $bodegaPrincipal ? $bodegaPrincipal->id : null; + }), + + Forms\Components\Select::make('producto_id') + ->label('Producto') + ->relationship('producto', 'nombre') + ->searchable() + ->required() + ->columnSpan(2) + ->live() + ->afterStateUpdated(function (Set $set, $state) { + $set('variante_id', null); + + if ($state) { + $producto = Producto::find($state); + if ($producto && $producto->variants()->exists()) { + Notification::make() + ->info() + ->title('Producto con variantes') + ->body('Selecciona una variante.') + ->send(); + } + } + }), + + Forms\Components\Select::make('variante_id') + ->label('Variante') + ->columnSpan(2) + ->options(function (Get $get) { + $productoId = $get('producto_id'); + if (!$productoId) return []; + + $producto = Producto::find($productoId); + if (!$producto || !$producto->variants()->exists()) return []; + + return ProductVariant::where('producto_id', $productoId) + ->with(['color', 'size']) + ->get() + ->mapWithKeys(function ($variant) { + $colorName = $variant->color ? $variant->color->name : 'Sin color'; + $sizeName = $variant->size ? $variant->size->name : 'Sin talla'; + return [$variant->id => "{$colorName} / {$sizeName}"]; + }); + }) + ->searchable() + ->live() + ->visible(function (Get $get) { + $productoId = $get('producto_id'); + if (!$productoId) return false; + + $producto = Producto::find($productoId); + return $producto && $producto->variants()->exists(); + }) + ->required(function (Get $get) { + $productoId = $get('producto_id'); + if (!$productoId) return false; + + $producto = Producto::find($productoId); + return $producto && $producto->variants()->exists(); + }), + + Forms\Components\TextInput::make('cantidad') + ->label('Cant.') + ->required() + ->numeric() + ->default(1) + ->columnSpan(1) + ->live(onBlur: true) + ->afterStateUpdated(function (Set $set, Get $get) { + $cantidad = (float) ($get('cantidad') ?? 0); + $precio = (float) ($get('precio_unitario') ?? 0); + $set('subtotal', $cantidad * $precio); + }), + + Forms\Components\TextInput::make('precio_unitario') + ->label('Precio Unit.') + ->required() + ->numeric() + ->prefix('$') + ->columnSpan(1) + ->live(onBlur: true) + ->afterStateUpdated(function (Set $set, Get $get) { + $cantidad = (float) ($get('cantidad') ?? 0); + $precio = (float) ($get('precio_unitario') ?? 0); + $set('subtotal', $cantidad * $precio); + }), + + Forms\Components\TextInput::make('subtotal') + ->label('Subtotal') + ->numeric() + ->prefix('$') + ->disabled() + ->dehydrated(true) + ->columnSpan(1), + + Forms\Components\TextInput::make('DetalleCompra') + ->label('Observaciones') + ->maxLength(255) + ->columnSpan(3), + ]) + ->columns(6) + ->defaultItems(1) + ->reorderable(false) + ->collapsible() + ->itemLabel(fn (array $state): ?string => + isset($state['producto_id']) + ? Producto::find($state['producto_id'])?->nombre ?? 'Producto' + : 'Nuevo producto' + ) + ->addActionLabel('+ Agregar producto') + ->live() + ->afterStateUpdated(function (Set $set, Get $get) { + // Calcular el total cuando cambian los detalles + $detalles = $get('detalles') ?? []; + $total = collect($detalles)->sum('subtotal'); + $set('total', $total); + }), + ]), + ]); + } + + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('id') + ->label('ID') + ->sortable(), + + Tables\Columns\TextColumn::make('proveedor.nombre') + ->label('Proveedor') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('total') + ->label('Total') + ->money('cop') + ->sortable() + ->alignEnd(), + + Tables\Columns\BadgeColumn::make('estado') + ->label('Estado') + ->colors([ + 'warning' => 'Pendiente', + 'success' => 'Recibida', + 'danger' => 'Anulada', + ]), + + Tables\Columns\TextColumn::make('detalles_count') + ->label('Items') + ->counts('detalles') + ->badge() + ->color('primary'), + + Tables\Columns\TextColumn::make('created_at') + ->label('Fecha') + ->dateTime('d/m/Y H:i') + ->sortable(), + + Tables\Columns\TextColumn::make('updated_at') + ->label('Actualizada') + ->dateTime('d/m/Y H:i') + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + DetallesRelationManagerRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListCompras::route('/'), + 'create' => Pages\CreateCompra::route('/create'), + 'edit' => Pages\EditCompra::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/CompraResource/Pages/CreateCompra.php b/app/Filament/Resources/CompraResource/Pages/CreateCompra.php new file mode 100644 index 0000000..071c63b --- /dev/null +++ b/app/Filament/Resources/CompraResource/Pages/CreateCompra.php @@ -0,0 +1,152 @@ +label('Descargar Plantilla Excel') + ->icon('heroicon-o-document-arrow-down') + ->color('info') + ->action(function () { + return Excel::download( + new PlantillaCompraExport(), + 'plantilla_compras.xlsx' + ); + }), + + Actions\Action::make('importar_excel') + ->label('Importar desde Excel') + ->icon('heroicon-o-arrow-down-tray') + ->color('success') + ->form([ + FileUpload::make('archivo') + ->label('Archivo Excel') + ->acceptedFileTypes([ + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'text/csv', + ]) + ->required() + ->helperText('Formato: Código de Barras, Producto, Cantidad, Precio Unitario, Bodega (opcional), Observaciones (opcional)') + ->disk('local') + ->directory('temp-imports'), + ]) + ->action(function (array $data) { + try { + $filePath = Storage::disk('local')->path($data['archivo']); + + $import = new CompraDetallesImport(); + Excel::import($import, $filePath); + + $previewData = $import->getPreviewData(); + $stats = $import->getStats(); + + // Mostrar vista preliminar en notificación + $message = "Total de filas: {$stats['total']}\n"; + $message .= "Válidas: {$stats['valid']}\n"; + $message .= "Con errores: {$stats['invalid']}\n"; + if ($stats['productos_creados'] > 0) { + $message .= "✨ Productos nuevos creados: {$stats['productos_creados']}\n"; + } + $message .= "Total estimado: $" . number_format($stats['total_amount'], 2); + + // Si hay errores, mostrarlos + if ($stats['invalid'] > 0) { + $errorMessages = collect($previewData) + ->filter(fn($item) => !$item['valid']) + ->map(fn($item) => "Fila {$item['row_number']}: " . implode(', ', $item['errors'])) + ->take(5) + ->implode("\n"); + + Notification::make() + ->warning() + ->title("Vista preliminar: {$stats['invalid']} filas con errores") + ->body($errorMessages . "\n\n" . $message) + ->persistent() + ->send(); + } else { + Notification::make() + ->success() + ->title('Vista preliminar de importación') + ->body($message) + ->persistent() + ->send(); + } + + // Cargar los datos directamente en el formulario + $detallesParaFormulario = $import->getDetallesForSave(); + + // Actualizar el formulario con los datos importados + $currentData = $this->data; + $currentData['detalles'] = array_merge( + $currentData['detalles'] ?? [], + $detallesParaFormulario + ); + + // Calcular el total + $currentData['total'] = collect($currentData['detalles'])->sum('subtotal'); + + $this->form->fill($currentData); + + // Limpiar archivo temporal + Storage::disk('local')->delete($data['archivo']); + + } catch (\Exception $e) { + Notification::make() + ->danger() + ->title('Error en la importación') + ->body($e->getMessage()) + ->send(); + } + }), + ]; + } + + protected function mutateFormDataBeforeCreate(array $data): array + { + // Calcular el total basado en los detalles + if (isset($data['detalles']) && is_array($data['detalles'])) { + $total = collect($data['detalles'])->sum('subtotal'); + $data['total'] = $total; + + // Agregar snapshots para cada detalle + foreach ($data['detalles'] as &$detalle) { + if (isset($detalle['producto_id'])) { + $producto = Producto::find($detalle['producto_id']); + $detalle['producto_nombre_snapshot'] = $producto?->nombre; + } + + if (isset($detalle['variante_id'])) { + $variante = ProductVariant::find($detalle['variante_id']); + if ($variante) { + $colorName = $variante->color?->name ?? 'Sin color'; + $sizeName = $variante->size?->name ?? 'Sin talla'; + $detalle['variante_info_snapshot'] = "$colorName / $sizeName"; + } + } + } + } else { + $data['total'] = 0; + } + + return $data; + } +} diff --git a/app/Filament/Resources/CompraResource/Pages/EditCompra.php b/app/Filament/Resources/CompraResource/Pages/EditCompra.php new file mode 100644 index 0000000..cf6942d --- /dev/null +++ b/app/Filament/Resources/CompraResource/Pages/EditCompra.php @@ -0,0 +1,186 @@ +label('Marcar como Recibida') + ->icon('heroicon-o-check-circle') + ->color('success') + ->visible(fn() => $this->record->estado === 'Pendiente') + ->requiresConfirmation() + ->modalHeading('Marcar compra como recibida') + ->modalDescription('Esto actualizará el stock en las bodegas según los productos de esta compra.') + ->action(function () { + $this->record->update(['estado' => 'Recibida']); + + Notification::make() + ->success() + ->title('Compra recibida') + ->body('El stock ha sido actualizado en las bodegas.') + ->send(); + + $this->redirect(static::getResource()::getUrl('edit', ['record' => $this->record])); + }), + + Actions\Action::make('descargar_plantilla') + ->label('Descargar Plantilla Excel') + ->icon('heroicon-o-document-arrow-down') + ->color('info') + ->action(function () { + return Excel::download( + new PlantillaCompraExport(), + 'plantilla_compras.xlsx' + ); + }), + + Actions\Action::make('importar_excel') + ->label('Importar desde Excel') + ->icon('heroicon-o-arrow-down-tray') + ->color('success') + ->form([ + FileUpload::make('archivo') + ->label('Archivo Excel') + ->acceptedFileTypes([ + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'text/csv', + ]) + ->required() + ->helperText('Formato: Código de Barras, Producto, Cantidad, Precio Unitario, Bodega (opcional), Observaciones (opcional)') + ->disk('local') + ->directory('temp-imports'), + ]) + ->action(function (array $data) { + try { + $filePath = Storage::disk('local')->path($data['archivo']); + + $import = new CompraDetallesImport(); + Excel::import($import, $filePath); + + $previewData = $import->getPreviewData(); + $stats = $import->getStats(); + + // Si hay errores, mostrarlos + if ($stats['invalid'] > 0) { + $errorMessages = collect($previewData) + ->filter(fn($item) => !$item['valid']) + ->map(fn($item) => "Fila {$item['row_number']}: " . implode(', ', $item['errors'])) + ->take(10) + ->implode("\n"); + + Notification::make() + ->warning() + ->title("Se encontraron {$stats['invalid']} filas con errores") + ->body($errorMessages) + ->persistent() + ->send(); + } + + // Obtener detalles válidos para agregar + $detallesValidos = $import->getDetallesForSave(); + + if (count($detallesValidos) > 0) { + // Agregar los detalles a la compra + foreach ($detallesValidos as $detalle) { + $this->record->detalles()->create($detalle); + } + + // Recalcular el total + $nuevoTotal = $this->record->detalles()->sum('subtotal'); + $this->record->update(['total' => $nuevoTotal]); + + $mensaje = "{$stats['valid']} productos agregados. Total: $" . number_format($stats['total_amount'], 2); + if ($stats['productos_creados'] > 0) { + $mensaje .= "\n✨ {$stats['productos_creados']} productos nuevos creados automáticamente"; + } + + Notification::make() + ->success() + ->title('Importación exitosa') + ->body($mensaje) + ->send(); + + // Si la compra está en estado Pendiente, preguntar si desea recibirla + if ($this->record->estado === 'Pendiente') { + Notification::make() + ->info() + ->title('Actualizar stock') + ->body('⚠️ La compra está en estado "Pendiente". Cambia el estado a "Recibida" para actualizar el stock en las bodegas.') + ->persistent() + ->send(); + } + + // Refrescar la página + $this->redirect(static::getResource()::getUrl('edit', ['record' => $this->record])); + } else { + Notification::make() + ->warning() + ->title('No hay datos válidos para importar') + ->send(); + } + + // Limpiar archivo temporal + Storage::disk('local')->delete($data['archivo']); + + } catch (\Exception $e) { + Notification::make() + ->danger() + ->title('Error en la importación') + ->body($e->getMessage()) + ->send(); + } + }), + + Actions\DeleteAction::make(), + ]; + } + + protected function mutateFormDataBeforeSave(array $data): array + { + // Calcular el total basado en los detalles + if (isset($data['detalles']) && is_array($data['detalles'])) { + $total = collect($data['detalles'])->sum('subtotal'); + $data['total'] = $total; + + // Agregar snapshots para cada detalle + foreach ($data['detalles'] as &$detalle) { + if (isset($detalle['producto_id'])) { + $producto = Producto::find($detalle['producto_id']); + $detalle['producto_nombre_snapshot'] = $producto?->nombre; + } + + if (isset($detalle['variante_id'])) { + $variante = ProductVariant::find($detalle['variante_id']); + if ($variante) { + $colorName = $variante->color?->name ?? 'Sin color'; + $sizeName = $variante->size?->name ?? 'Sin talla'; + $detalle['variante_info_snapshot'] = "$colorName / $sizeName"; + } + } + } + } else { + $data['total'] = 0; + } + + return $data; + } +} diff --git a/app/Filament/Resources/CompraResource/Pages/ListCompras.php b/app/Filament/Resources/CompraResource/Pages/ListCompras.php new file mode 100644 index 0000000..9c71f4d --- /dev/null +++ b/app/Filament/Resources/CompraResource/Pages/ListCompras.php @@ -0,0 +1,31 @@ +label('Descargar Plantilla Excel') + ->icon('heroicon-o-document-arrow-down') + ->color('info') + ->action(function () { + return Excel::download( + new PlantillaCompraExport(), + 'plantilla_compras.xlsx' + ); + }), + Actions\CreateAction::make(), + ]; + } +} diff --git a/app/Filament/Resources/CompraResource/RelationManagers/DetallesRelationManagerRelationManager.php b/app/Filament/Resources/CompraResource/RelationManagers/DetallesRelationManagerRelationManager.php new file mode 100644 index 0000000..f770af1 --- /dev/null +++ b/app/Filament/Resources/CompraResource/RelationManagers/DetallesRelationManagerRelationManager.php @@ -0,0 +1,275 @@ +schema([ + TextInput::make('codigo_escaneado') + ->label('Escanear código de barras') + ->live() + ->afterStateUpdated(function (callable $set, $state) { + // Buscar en ProductVariant + $variant = ProductVariant::where('barcode', $state)->first(); + if ($variant) { + $set('producto_id', $variant->producto_id); + $set('variante_id', $variant->id); + + // Validación defensiva para evitar error "name" on null + $colorName = $variant->color ? $variant->color->name : 'Sin color'; + $sizeName = $variant->size ? $variant->size->name : 'Sin talla'; + + Notification::make() + ->success() + ->title('Variante encontrada') + ->body("Producto: {$variant->producto->nombre} - Variante: {$colorName}/{$sizeName}") + ->send(); + return; + } + + // Buscar en Producto + $producto = Producto::where('codigo_barras', $state)->first(); + if ($producto) { + $set('producto_id', $producto->id); + $set('variante_id', null); + + if ($producto->variants()->exists()) { + Notification::make() + ->warning() + ->title('Producto con variantes') + ->body('Este producto tiene variantes. Por favor selecciona una variante específica.') + ->send(); + } else { + Notification::make() + ->success() + ->title('Producto encontrado') + ->body("Producto: {$producto->nombre}") + ->send(); + } + } else { + Notification::make() + ->warning() + ->title('Código no encontrado') + ->body('No se encontró ningún producto o variante con este código.') + ->send(); + } + }), + + Select::make('bodega_id') + ->label('Bodega de Destino') + ->relationship('bodega', 'nombre') + ->searchable() + ->required() + ->default(function () { + // Buscar bodega "Principal" como default + $bodegaPrincipal = Bodega::where('nombre', 'Principal')->first(); + return $bodegaPrincipal ? $bodegaPrincipal->id : null; + }) + ->helperText('Selecciona la bodega donde se almacenará este producto'), + + Select::make('producto_id') + ->label('Producto') + ->relationship('producto', 'nombre') + ->searchable() + ->required() + ->live() + ->afterStateUpdated(function (callable $set, $state) { + // Limpiar variante cuando cambia el producto + $set('variante_id', null); + + if ($state) { + $producto = Producto::find($state); + if ($producto && $producto->variants()->exists()) { + Notification::make() + ->info() + ->title('Producto con variantes') + ->body('Este producto tiene variantes disponibles. Por favor selecciona una.') + ->send(); + } + } + }), + + Select::make('variante_id') + ->label('Variante') + ->options(function (callable $get) { + $productoId = $get('producto_id'); + if (!$productoId) { + return []; + } + + $producto = Producto::find($productoId); + if (!$producto || !$producto->variants()->exists()) { + return []; + } + + return ProductVariant::where('producto_id', $productoId) + ->with(['color', 'size']) + ->get() + ->mapWithKeys(function ($variant) { + // Validación defensiva para evitar error "name" on null + $colorName = $variant->color ? $variant->color->name : 'Sin color'; + $sizeName = $variant->size ? $variant->size->name : 'Sin talla'; + + return [ + $variant->id => "{$colorName} / {$sizeName}", + ]; + }); + }) + ->searchable() + ->live() + ->visible(function (callable $get) { + $productoId = $get('producto_id'); + if (!$productoId) return false; + + $producto = Producto::find($productoId); + return $producto && $producto->variants()->exists(); + }) + ->required(function (callable $get) { + $productoId = $get('producto_id'); + if (!$productoId) return false; + + $producto = Producto::find($productoId); + return $producto && $producto->variants()->exists(); + }) + ->helperText(function (callable $get) { + $productoId = $get('producto_id'); + if (!$productoId) return null; + + $producto = Producto::find($productoId); + if (!$producto || !$producto->variants()->exists()) { + return null; + } + + return 'Este producto requiere seleccionar una variante específica.'; + }), + + TextInput::make('cantidad') + ->required() + ->numeric() + ->live() + ->helperText('Cantidad en unidades individuales') + ->afterStateUpdated(function (callable $set, callable $get) { + $cantidad = (float) $get('cantidad'); + $precio = (float) $get('precio_unitario'); + $set('subtotal', $cantidad * $precio); + }), + + TextInput::make('precio_unitario') + ->required() + ->numeric() + ->prefix('$') + ->live() + ->helperText('Precio por unidad individual') + ->afterStateUpdated(function (callable $set, callable $get) { + $cantidad = (float) $get('cantidad'); + $precio = (float) $get('precio_unitario'); + $set('subtotal', $cantidad * $precio); + }), + + TextInput::make('subtotal') + ->numeric() + ->prefix('$') + ->disabled() + ->dehydrated(true), // guarda el valor aunque esté deshabilitado + + TextInput::make('DetalleCompra') + ->label('Detalle/Observaciones') + ->maxLength(255) + ->helperText('Información adicional sobre esta compra (opcional)'), + ]); + } + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('DetalleCompra') + ->columns([ + Tables\Columns\TextColumn::make('bodega.nombre') + ->label('Bodega') + ->badge() + ->color('primary'), + + Tables\Columns\TextColumn::make('producto_nombre') + ->label('Producto') + ->searchable() + ->sortable() + ->color(fn($record) => $record->producto_id ? 'primary' : 'warning') + ->icon(fn($record) => $record->producto_id ? null : 'heroicon-o-archive-box-x-mark') + ->tooltip(fn($record) => $record->producto_id ? null : 'Producto eliminado - información histórica'), + + Tables\Columns\TextColumn::make('variante_info') + ->label('Variante') + ->badge() + ->color(function ($record) { + if ($record->variante_id) return 'success'; + if ($record->variante_info_snapshot) return 'warning'; + return 'gray'; + }) + ->formatStateUsing(fn($record) => $record->variante_info ?: '—') + ->tooltip(function ($record) { + if ($record->variante_id) return null; + if ($record->variante_info_snapshot) return 'Variante eliminada - información histórica'; + return 'Sin variante'; + }), + + Tables\Columns\TextColumn::make('cantidad') + ->label('Cantidad') + ->alignEnd(), + + Tables\Columns\TextColumn::make('precio_unitario') + ->label('Precio Unitario') + ->money('cop') + ->alignEnd(), + + Tables\Columns\TextColumn::make('subtotal') + ->label('Subtotal') + ->money('cop') + ->alignEnd() + ->weight('bold') + ->color('primary'), + + Tables\Columns\TextColumn::make('DetalleCompra') + ->label('Detalle') + ->limit(30) + ->toggleable(isToggledHiddenByDefault: true), + ]) + + ->filters([ + // + ]) + ->headerActions([ + Tables\Actions\CreateAction::make(), + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } +} diff --git a/app/Filament/Resources/DetalleCompraResource.php b/app/Filament/Resources/DetalleCompraResource.php new file mode 100644 index 0000000..57c8937 --- /dev/null +++ b/app/Filament/Resources/DetalleCompraResource.php @@ -0,0 +1,109 @@ +user()->can('ver detalle de compras'); + } + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\Select::make('compra_id') + ->relationship('compra', 'id') + ->required(), + Forms\Components\Select::make('producto_id') + ->relationship('producto', 'id') + ->required(), + Forms\Components\TextInput::make('cantidad') + ->required() + ->numeric(), + Forms\Components\TextInput::make('precio_unitario') + ->required() + ->numeric(), + Forms\Components\TextInput::make('subtotal') + ->required() + ->numeric(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('compra.id') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('producto.id') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('cantidad') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('precio_unitario') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('subtotal') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListDetalleCompras::route('/'), + 'create' => Pages\CreateDetalleCompra::route('/create'), + 'edit' => Pages\EditDetalleCompra::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/DetalleCompraResource/Pages/CreateDetalleCompra.php b/app/Filament/Resources/DetalleCompraResource/Pages/CreateDetalleCompra.php new file mode 100644 index 0000000..1bc91c2 --- /dev/null +++ b/app/Filament/Resources/DetalleCompraResource/Pages/CreateDetalleCompra.php @@ -0,0 +1,12 @@ +user()->can('ver detalle de ventas'); + } + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\Select::make('venta_id') + ->relationship('venta', 'id') + ->required(), + Forms\Components\Select::make('producto_id') + ->relationship('producto', 'id') + ->required(), + Forms\Components\TextInput::make('cantidad') + ->required() + ->numeric(), + Forms\Components\TextInput::make('precio_unitario') + ->required() + ->numeric(), + Forms\Components\TextInput::make('subtotal') + ->required() + ->numeric(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('venta.id') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('producto.id') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('cantidad') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('precio_unitario') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('subtotal') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListDetalleVentas::route('/'), + 'create' => Pages\CreateDetalleVenta::route('/create'), + 'edit' => Pages\EditDetalleVenta::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/DetalleVentaResource/Pages/CreateDetalleVenta.php b/app/Filament/Resources/DetalleVentaResource/Pages/CreateDetalleVenta.php new file mode 100644 index 0000000..211e2c0 --- /dev/null +++ b/app/Filament/Resources/DetalleVentaResource/Pages/CreateDetalleVenta.php @@ -0,0 +1,12 @@ +query(self::getInformeQuery()) + ->columns([ + Tables\Columns\TextColumn::make('producto_nombre') + ->label('Producto') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('categoria_nombre') + ->label('Categoría') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('total_vendido') + ->label('Cantidad Vendida') + ->alignCenter() + ->sortable() + ->formatStateUsing(function ($state, $record) { + $unidadMedida = $record->unidad_medida ?? 'unidad'; + $cantidadEnUnidad = Producto::convertirDesdeUnidades($state, $unidadMedida); + $nombreUnidad = explode(' ', Producto::getUnidadesMedida()[$unidadMedida])[0]; + return "{$cantidadEnUnidad} {$nombreUnidad}"; + }) + ->tooltip(function ($state, $record) { + $unidadMedida = $record->unidad_medida ?? 'unidad'; + $cantidadEnUnidad = Producto::convertirDesdeUnidades($state, $unidadMedida); + return "Cantidad en unidades: {$state}\nCantidad en {$unidadMedida}: {$cantidadEnUnidad}"; + }), + + Tables\Columns\TextColumn::make('precio_compra_unitario') + ->label('Precio Compra Actual') + ->money('COP') + ->alignEnd() + ->sortable(), + + Tables\Columns\TextColumn::make('promedio_ponderado_compra') + ->label('Promedio Ponderado Compra') + ->money('COP') + ->alignEnd() + ->sortable() + ->tooltip('Precio promedio de compra ponderado por cantidades compradas'), + + Tables\Columns\TextColumn::make('valor_total_compra') + ->label('Valor Total Compra') + ->money('COP') + ->alignEnd() + ->sortable(), + + Tables\Columns\TextColumn::make('precio_venta_promedio') + ->label('Precio Venta Promedio') + ->money('COP') + ->alignEnd() + ->sortable(), + + Tables\Columns\TextColumn::make('promedio_ponderado') + ->label('Promedio Ponderado') + ->money('COP') + ->alignEnd() + ->sortable() + ->tooltip('Precio promedio ponderado por cantidad vendida'), + + Tables\Columns\TextColumn::make('margen_beneficio') + ->label('Margen %') + ->alignCenter() + ->sortable() + ->getStateUsing(function ($record) { + $precioCompra = $record->precio_compra_unitario; + $precioVenta = $record->precio_venta_promedio; + + if ($precioCompra > 0) { + $margen = (($precioVenta - $precioCompra) / $precioCompra) * 100; + return round($margen, 2); + } + return 0; + }) + ->formatStateUsing(function ($state) { + $color = $state >= 0 ? 'success' : 'danger'; + $icon = $state >= 0 ? '📈' : '📉'; + return "{$icon} {$state}%"; + }), + ]) + ->defaultSort('valor_total_compra', 'desc') + ->filters([ + Tables\Filters\Filter::make('fecha_rango') + ->form([ + Forms\Components\DatePicker::make('fecha_desde') + ->label('Fecha Desde') + ->default(Carbon::now()->startOfMonth()), + + Forms\Components\DatePicker::make('fecha_hasta') + ->label('Fecha Hasta') + ->default(Carbon::now()->endOfMonth()), + ]) + ->query(function (Builder $query, array $data): Builder { + return $query + ->when( + $data['fecha_desde'], + fn (Builder $query, $date): Builder => $query->whereDate('ventas.created_at', '>=', $date), + ) + ->when( + $data['fecha_hasta'], + fn (Builder $query, $date): Builder => $query->whereDate('ventas.created_at', '<=', $date), + ); + }) + ->indicateUsing(function (array $data): array { + $indicators = []; + if ($data['fecha_desde']) { + $indicators['fecha_desde'] = 'Desde: ' . Carbon::parse($data['fecha_desde'])->format('d/m/Y'); + } + if ($data['fecha_hasta']) { + $indicators['fecha_hasta'] = 'Hasta: ' . Carbon::parse($data['fecha_hasta'])->format('d/m/Y'); + } + return $indicators; + }), + + Tables\Filters\SelectFilter::make('categoria') + ->options(\App\Models\Categoria::pluck('nombre', 'id')) + ->query(function (Builder $query, array $data): Builder { + if (!empty($data['value'])) { + return $query->where('categorias.id', $data['value']); + } + return $query; + }) + ->searchable() + ->preload(), + ]) + ->actions([ + // No actions needed for reports + ]) + ->bulkActions([ + // No bulk actions for reports + ]) + ->emptyStateHeading('No hay ventas en el período seleccionado') + ->emptyStateDescription('Ajuste los filtros de fecha para ver resultados') + ->poll('60s'); // Actualizar cada minuto + } + + /** + * Query personalizado para el informe de promedio ponderado + */ + protected static function getInformeQuery(): Builder + { + return DetalleVenta::query() + ->select([ + 'productos.id as id', // Filament necesita 'id' como clave del registro + 'productos.id as producto_id', // Mantener para compatibilidad + 'productos.nombre as producto_nombre', + 'productos.precio_compra as precio_compra_unitario', + 'productos.unidad_medida', + 'categorias.nombre as categoria_nombre', + DB::raw('SUM(detalle_ventas.cantidad) as total_vendido'), + DB::raw('ROUND(AVG(detalle_ventas.precio_unitario), 2) as precio_venta_promedio'), + // Promedio ponderado real: suma de (cantidad * precio) / suma de cantidades + DB::raw('ROUND(SUM(detalle_ventas.cantidad * detalle_ventas.precio_unitario) / SUM(detalle_ventas.cantidad), 2) as promedio_ponderado'), + // Promedio ponderado de compra basado en compras reales + DB::raw('COALESCE( + (SELECT ROUND(SUM(dc.cantidad * dc.precio_unitario) / SUM(dc.cantidad), 2) + FROM detalle_compras dc + INNER JOIN compras c ON dc.compra_id = c.id + WHERE dc.producto_id = productos.id AND c.estado = \'Recibida\'), + CAST(productos.precio_compra AS DECIMAL(10,2)) + ) as promedio_ponderado_compra'), + DB::raw('COUNT(DISTINCT ventas.id) as numero_ventas'), + DB::raw('MIN(ventas.created_at) as primera_venta'), + DB::raw('MAX(ventas.created_at) as ultima_venta'), + // Agregar el campo calculado para poder ordenar por él con cast explícito + DB::raw('SUM(detalle_ventas.cantidad) * CAST(productos.precio_compra AS DECIMAL(10,2)) as valor_total_compra'), + ]) + ->join('productos', 'detalle_ventas.producto_id', '=', 'productos.id') + ->join('categorias', 'productos.categoria_id', '=', 'categorias.id') + ->join('ventas', 'detalle_ventas.venta_id', '=', 'ventas.id') + ->groupBy([ + 'productos.id', + 'productos.nombre', + 'productos.precio_compra', + 'productos.unidad_medida', + 'categorias.nombre' + ]) + ->havingRaw('SUM(detalle_ventas.cantidad) > 0'); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListInformes::route('/'), + ]; + } +} \ No newline at end of file diff --git a/app/Filament/Resources/InformeResource/Pages/ListInformes.php b/app/Filament/Resources/InformeResource/Pages/ListInformes.php new file mode 100644 index 0000000..c335efc --- /dev/null +++ b/app/Filament/Resources/InformeResource/Pages/ListInformes.php @@ -0,0 +1,127 @@ +label('Ver Resumen') + ->icon('heroicon-o-chart-pie') + ->color('info') + ->modalHeading('Resumen Ejecutivo - Promedio Ponderado') + ->modalContent(function () { + return view('filament.pages.informe-resumen', [ + 'resumen' => $this->getResumenEjecutivo() + ]); + }) + ->modalWidth('6xl'), + ]; + } + + protected function getHeaderWidgets(): array + { + return [ + InformeResource\Widgets\ResumenPromedioWidget::class, + ]; + } + + /** + * Calcular resumen ejecutivo del período + */ + protected function getResumenEjecutivo(): array + { + $filtros = request()->get('tableFilters', []); + $fechaDesde = $filtros['fecha_rango']['fecha_desde'] ?? Carbon::now()->startOfMonth()->format('Y-m-d'); + $fechaHasta = $filtros['fecha_rango']['fecha_hasta'] ?? Carbon::now()->endOfMonth()->format('Y-m-d'); + + $query = DetalleVenta::query() + ->join('productos', 'detalle_ventas.producto_id', '=', 'productos.id') + ->join('ventas', 'detalle_ventas.venta_id', '=', 'ventas.id') + ->whereDate('ventas.created_at', '>=', $fechaDesde) + ->whereDate('ventas.created_at', '<=', $fechaHasta); + + // Cálculos principales + $totalProductosVendidos = $query->sum('detalle_ventas.cantidad'); + $valorTotalCompra = $query->sum(DB::raw('detalle_ventas.cantidad * CAST(productos.precio_compra AS DECIMAL)')); + $valorTotalVenta = $query->sum(DB::raw('detalle_ventas.cantidad * detalle_ventas.precio_unitario')); + + $promedioCompra = $totalProductosVendidos > 0 + ? $valorTotalCompra / $totalProductosVendidos + : 0; + + $promedioVenta = $totalProductosVendidos > 0 + ? $valorTotalVenta / $totalProductosVendidos + : 0; + + $margenTotal = $valorTotalCompra > 0 + ? (($valorTotalVenta - $valorTotalCompra) / $valorTotalCompra) * 100 + : 0; + + // Top productos por valor de compra + $topProductos = DetalleVenta::query() + ->select([ + 'productos.nombre', + DB::raw('SUM(detalle_ventas.cantidad) as cantidad_vendida'), + DB::raw('SUM(detalle_ventas.cantidad * CAST(productos.precio_compra AS DECIMAL)) as valor_compra_total'), + 'productos.precio_compra' + ]) + ->join('productos', 'detalle_ventas.producto_id', '=', 'productos.id') + ->join('ventas', 'detalle_ventas.venta_id', '=', 'ventas.id') + ->whereDate('ventas.created_at', '>=', $fechaDesde) + ->whereDate('ventas.created_at', '<=', $fechaHasta) + ->groupBy('productos.id', 'productos.nombre', 'productos.precio_compra') + ->orderByRaw('SUM(detalle_ventas.cantidad * CAST(productos.precio_compra AS DECIMAL)) desc') + ->limit(10) + ->get(); + + // Análisis por categoría + $categorias = DetalleVenta::query() + ->select([ + 'categorias.nombre as categoria', + DB::raw('SUM(detalle_ventas.cantidad) as cantidad_vendida'), + DB::raw('SUM(detalle_ventas.cantidad * CAST(productos.precio_compra AS DECIMAL)) as valor_compra_total'), + DB::raw('AVG(CAST(productos.precio_compra AS DECIMAL)) as precio_compra_promedio'), + DB::raw('COUNT(DISTINCT productos.id) as productos_diferentes'), + ]) + ->join('productos', 'detalle_ventas.producto_id', '=', 'productos.id') + ->join('categorias', 'productos.categoria_id', '=', 'categorias.id') + ->join('ventas', 'detalle_ventas.venta_id', '=', 'ventas.id') + ->whereDate('ventas.created_at', '>=', $fechaDesde) + ->whereDate('ventas.created_at', '<=', $fechaHasta) + ->groupBy('categorias.id', 'categorias.nombre') + ->orderByRaw('SUM(detalle_ventas.cantidad * CAST(productos.precio_compra AS DECIMAL)) desc') + ->get(); + + return [ + 'periodo' => [ + 'fecha_desde' => Carbon::parse($fechaDesde)->format('d/m/Y'), + 'fecha_hasta' => Carbon::parse($fechaHasta)->format('d/m/Y'), + 'dias' => Carbon::parse($fechaDesde)->diffInDays(Carbon::parse($fechaHasta)) + 1, + ], + 'totales' => [ + 'productos_vendidos' => $totalProductosVendidos, + 'valor_total_compra' => $valorTotalCompra, + 'valor_total_venta' => $valorTotalVenta, + 'promedio_compra' => $promedioCompra, + 'promedio_venta' => $promedioVenta, + 'margen_total' => $margenTotal, + 'beneficio_total' => $valorTotalVenta - $valorTotalCompra, + ], + 'top_productos' => $topProductos, + 'categorias' => $categorias, + ]; + } +} \ No newline at end of file diff --git a/app/Filament/Resources/InformeResource/Widgets/ResumenPromedioWidget.php b/app/Filament/Resources/InformeResource/Widgets/ResumenPromedioWidget.php new file mode 100644 index 0000000..c1ee9ee --- /dev/null +++ b/app/Filament/Resources/InformeResource/Widgets/ResumenPromedioWidget.php @@ -0,0 +1,66 @@ +get('tableFilters', []); + $fechaDesde = $filtros['fecha_rango']['fecha_desde'] ?? Carbon::now()->startOfMonth()->format('Y-m-d'); + $fechaHasta = $filtros['fecha_rango']['fecha_hasta'] ?? Carbon::now()->endOfMonth()->format('Y-m-d'); + + $resumen = $this->calcularResumen($fechaDesde, $fechaHasta); + + return [ + Stat::make('Total Productos Vendidos', number_format($resumen['total_productos'])) + ->description('Unidades vendidas en el período') + ->descriptionIcon('heroicon-m-cube') + ->color('primary'), + + Stat::make('Promedio Ponderado Compra', '$' . number_format($resumen['promedio_compra'], 0)) + ->description('Costo promedio por unidad') + ->descriptionIcon('heroicon-m-banknotes') + ->color('warning'), + + Stat::make('Valor Total Invertido', '$' . number_format($resumen['valor_total_compra'], 0)) + ->description('Inversión total en productos vendidos') + ->descriptionIcon('heroicon-m-chart-bar') + ->color('danger'), + + Stat::make('Margen Promedio', round($resumen['margen_promedio'], 2) . '%') + ->description($resumen['margen_promedio'] >= 0 ? 'Beneficio promedio' : 'Pérdida promedio') + ->descriptionIcon($resumen['margen_promedio'] >= 0 ? 'heroicon-m-arrow-trending-up' : 'heroicon-m-arrow-trending-down') + ->color($resumen['margen_promedio'] >= 0 ? 'success' : 'danger'), + ]; + } + + protected function calcularResumen(string $fechaDesde, string $fechaHasta): array + { + $query = DetalleVenta::query() + ->join('productos', 'detalle_ventas.producto_id', '=', 'productos.id') + ->join('ventas', 'detalle_ventas.venta_id', '=', 'ventas.id') + ->whereDate('ventas.created_at', '>=', $fechaDesde) + ->whereDate('ventas.created_at', '<=', $fechaHasta); + + $totalProductos = $query->sum('detalle_ventas.cantidad'); + $valorTotalCompra = $query->sum(DB::raw('detalle_ventas.cantidad * CAST(productos.precio_compra AS DECIMAL)')); + $valorTotalVenta = $query->sum(DB::raw('detalle_ventas.cantidad * detalle_ventas.precio_unitario')); + + $promedioCompra = $totalProductos > 0 ? $valorTotalCompra / $totalProductos : 0; + $margenPromedio = $valorTotalCompra > 0 ? (($valorTotalVenta - $valorTotalCompra) / $valorTotalCompra) * 100 : 0; + + return [ + 'total_productos' => $totalProductos, + 'valor_total_compra' => $valorTotalCompra, + 'promedio_compra' => $promedioCompra, + 'margen_promedio' => $margenPromedio, + ]; + } +} \ No newline at end of file diff --git a/app/Filament/Resources/MovimientoCajaResource.php b/app/Filament/Resources/MovimientoCajaResource.php new file mode 100644 index 0000000..e9f8330 --- /dev/null +++ b/app/Filament/Resources/MovimientoCajaResource.php @@ -0,0 +1,106 @@ +user()->can('ver movimientos de caja'); + } + + public static function form(Form $form): Form + { + return $form + ->schema([ + Select::make('caja_id') + ->label('Caja (Fecha de apertura)') + ->options(function () { + return \App\Models\Caja::where('estado', 'Abierta') + ->pluck('created_at', 'id') + ->mapWithKeys(function ($createdAt, $id) { + return [$id => \Carbon\Carbon::parse($createdAt)->format('d/m/Y H:i')]; + }); + }) + ->required(), + + Forms\Components\TextInput::make('tipo') + ->required(), + + Forms\Components\TextInput::make('monto') + ->required() + ->numeric(), + + Forms\Components\Textarea::make('descripcion') + ->columnSpanFull(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('caja.created_at') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('tipo'), + Tables\Columns\TextColumn::make('monto') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListMovimientoCajas::route('/'), + 'create' => Pages\CreateMovimientoCaja::route('/create'), + 'edit' => Pages\EditMovimientoCaja::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/MovimientoCajaResource/Pages/CreateMovimientoCaja.php b/app/Filament/Resources/MovimientoCajaResource/Pages/CreateMovimientoCaja.php new file mode 100644 index 0000000..7b4dca6 --- /dev/null +++ b/app/Filament/Resources/MovimientoCajaResource/Pages/CreateMovimientoCaja.php @@ -0,0 +1,12 @@ +user()->can('ver permisos'); + } + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('name') + ->required() + ->unique() + ->maxLength(255), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('id')->sortable(), + Tables\Columns\TextColumn::make('name')->sortable()->searchable(), + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]) + ->bulkActions([ + Tables\Actions\DeleteBulkAction::make(), + ]); + } + + public static function getRelations(): array + { + return []; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListPermissions::route('/'), + 'create' => Pages\CreatePermission::route('/create'), + 'edit' => Pages\EditPermission::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/PermissionResource/Pages/CreatePermission.php b/app/Filament/Resources/PermissionResource/Pages/CreatePermission.php new file mode 100644 index 0000000..7497dc6 --- /dev/null +++ b/app/Filament/Resources/PermissionResource/Pages/CreatePermission.php @@ -0,0 +1,12 @@ +can('ver variantes'); + } + + protected static ?string $model = ProductVariant::class; + + protected static ?string $navigationIcon = 'heroicon-o-tag'; + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\Select::make('producto_id') + ->relationship('producto', 'nombre') + ->searchable() + ->required() + ->reactive() + ->afterStateUpdated(fn($set, $get, $component) => self::updateSkuAndBarcode($set, $get, $component)), + + Forms\Components\Select::make('color_id') + ->relationship('color', 'name') + ->searchable() + ->required() + ->reactive() + ->afterStateUpdated(fn($set, $get, $component) => self::updateSkuAndBarcode($set, $get, $component)), + + Forms\Components\Select::make('size_id') + ->relationship('size', 'name') + ->searchable() + ->required() + ->reactive() + ->afterStateUpdated(fn($set, $get, $component) => self::updateSkuAndBarcode($set, $get, $component)), + + Forms\Components\TextInput::make('sku') + ->label('SKU') + ->required() + ->maxLength(50) + ->dehydrated(), // Se guarda en la base de datos + TextInput::make('barcode') + ->label('Código de Barras') + ->required() + ->length(13) + ->dehydrated() + ->suffixAction( + Action::make('imprimirQr') + ->icon('heroicon-o-printer') + ->color('primary') + ->hidden(fn($record) => is_null($record)) + ->action(fn($state) => redirect()->route('imprimir.barcode', ['barcode' => $state])) + ->hidden(fn($record) => is_null($record)) + ), + + Forms\Components\Section::make('Asignación de Bodega') + ->schema([ + Forms\Components\Select::make('bodega_id') + ->label('Bodega Inicial') + ->options(\App\Models\Bodega::pluck('nombre', 'id')) + ->required() + ->searchable() + ->preload() + ->default(function () { + // Intentar obtener la bodega principal como default + $bodegaPrincipal = \App\Models\Bodega::where('nombre', 'Principal')->first(); + return $bodegaPrincipal?->id; + }) + ->helperText('Seleccione la bodega donde se asignará el stock inicial de esta variante'), + + Forms\Components\TextInput::make('stock_inicial') + ->label('Stock Inicial') + ->numeric() + ->required() + ->default(0) + ->minValue(0) + ->helperText('Stock que se asignará en la bodega seleccionada'), + + Forms\Components\Placeholder::make('info_bodega') + ->label('Información') + ->content('La variante se creará con el stock especificado en la bodega seleccionada. Podrá distribuir a otras bodegas posteriormente.') + ]) + ->columns(2) + ->hiddenOn('edit'), // Solo mostrar en creación + + ]); + } + + + protected static function updateSkuAndBarcode($set, $get, $component) + { + $producto = $get('producto_id') ? \App\Models\Producto::find($get('producto_id')) : null; + $color = $get('color_id') ? \App\Models\Color::find($get('color_id')) : null; + $size = $get('size_id') ? \App\Models\Size::find($get('size_id')) : null; + + $exists = ProductVariant::where('producto_id', $get('producto_id')) + ->where('color_id', $get('color_id')) + ->where('size_id', $get('size_id')) + ->exists(); + + if ($exists) { + // Mostrar notificación en Filament + Notification::make() + ->title('Error') + ->body('Esta combinación de producto, color y talla ya existe.') + ->danger() + ->send(); + } + + // Generar SKU basado en el producto, color y talla + $baseSku = strtoupper(substr($producto?->nombre ?? 'XX', 0, 2)) . '-' . + strtoupper(substr($color?->name ?? 'XX', 0, 2)) . '-' . + strtoupper(substr($size?->name ?? 'XX', 0, 2)); + + // Asegurar SKU único + $sku = $baseSku; + $counter = 1; + while (ProductVariant::where('sku', $sku)->exists()) { + $sku = $baseSku . '-' . $counter; + $counter++; + } + + // Obtener datos para el código de barras + $countryCode = '57'; // Código de país (puedes cambiarlo) + $categoryId = $producto?->categoria_id ?? 00; + $productId = $producto?->id ?? 00000; + $variantId = ProductVariant::where('producto_id',$productId)->count() ?? 0; + $variantId += 1; + + + // Generar código de barras estructurado + $eanService = app(\App\Services\EAN13Service::class); + $barcode = $eanService->generateUniqueBarcode($countryCode, $categoryId, $productId, $variantId); + + // Asignar valores al formulario + $set('sku', $sku); + $set('barcode', $barcode); + } + + + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('producto.nombre') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('color.name') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('size.name') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('stock_total') + ->label('Stock Total') + ->getStateUsing(function (ProductVariant $record): string { + $stockTotal = $record->getStockEfectivo(); + $bodegas = $record->bodegas()->count(); + return "{$stockTotal} ({$bodegas} bodegas)"; + }) + ->tooltip('Stock total distribuido en todas las bodegas') + ->sortable(query: function ($query, $direction) { + return $query->withSum('bodegas as stock_total', 'variante_bodega.stock') + ->orderBy('stock_total', $direction); + }), + Tables\Columns\TextColumn::make('sku') + ->label('SKU') + ->searchable(), + Tables\Columns\TextColumn::make('barcode') + ->action(fn($record) => redirect()->route('imprimir.barcode', ['barcode' => $record->barcode])) + ->tooltip('Imprimir código de barras'), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + SelectFilter::make('producto_id') + ->label('Producto') + ->relationship('producto', 'nombre') // Relación con el modelo producto + ->preload() // Precargar opcionesπ + ->searchable(), // Permitir búsqueda en el filtro + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + RelationManagers\BodegasRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListProductVariants::route('/'), + 'create' => Pages\CreateProductVariant::route('/create'), + 'edit' => Pages\EditProductVariant::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/ProductVariantResource/Pages/CreateProductVariant.php b/app/Filament/Resources/ProductVariantResource/Pages/CreateProductVariant.php new file mode 100644 index 0000000..0bb998c --- /dev/null +++ b/app/Filament/Resources/ProductVariantResource/Pages/CreateProductVariant.php @@ -0,0 +1,60 @@ + $bodegaId]); + Log::info('Stock inicial extraído:', ['stock_inicial' => $stockInicial]); + + // Remover campos que no pertenecen al modelo ProductVariant + unset($data['bodega_id'], $data['stock_inicial']); + + // Asegurar que stock esté en 0 en el modelo principal + $data['stock'] = 0; + + // Crear la variante + $variante = ProductVariant::create($data); + + Log::info('Variante creada:', ['id' => $variante->id]); + + // Asignar a la bodega si se especificó + if ($bodegaId) { + $variante->bodegas()->attach($bodegaId, ['stock' => $stockInicial]); + + Log::info('Relación bodega creada:', [ + 'variante_id' => $variante->id, + 'bodega_id' => $bodegaId, + 'stock' => $stockInicial + ]); + + $bodegaNombre = \App\Models\Bodega::find($bodegaId)->nombre; + + Notification::make() + ->title('Variante creada exitosamente') + ->body("La variante se asignó a la bodega '{$bodegaNombre}' con stock de {$stockInicial} unidades.") + ->success() + ->send(); + } + + return $variante; + } +} diff --git a/app/Filament/Resources/ProductVariantResource/Pages/EditProductVariant.php b/app/Filament/Resources/ProductVariantResource/Pages/EditProductVariant.php new file mode 100644 index 0000000..cef1f87 --- /dev/null +++ b/app/Filament/Resources/ProductVariantResource/Pages/EditProductVariant.php @@ -0,0 +1,21 @@ +schema([ + Forms\Components\Select::make('bodega_id') + ->label('Bodega') + ->options(\App\Models\Bodega::pluck('nombre', 'id')) + ->required() + ->searchable() + ->preload(), + + Forms\Components\TextInput::make('stock') + ->label('Stock en esta Bodega') + ->numeric() + ->required() + ->default(0) + ->minValue(0) + ->helperText('Cantidad de esta variante en la bodega seleccionada'), + ]); + } + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('nombre') + ->columns([ + Tables\Columns\TextColumn::make('nombre') + ->label('Bodega') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('pivot.stock') + ->label('Stock') + ->alignCenter() + ->sortable() + ->formatStateUsing(function ($state) { + $estado = $state > 0 ? '✅' : '⚠️'; + return "{$estado} {$state} unidades"; + }) + ->tooltip(function ($state) { + return "Stock en unidades: {$state}"; + }), + + Tables\Columns\TextColumn::make('pivot.updated_at') + ->label('Última Actualización') + ->dateTime('d/m/Y H:i') + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + Tables\Filters\Filter::make('con_stock') + ->label('Solo con Stock') + ->query(fn($query) => $query->where('variante_bodega.stock', '>', 0)), + ]) + ->headerActions([ + Tables\Actions\CreateAction::make() + ->label('Asignar a Bodega') + ->modalHeading('Asignar Variante a Bodega') + ->action(function (array $data): void { + $variante = $this->getOwnerRecord(); + $bodegaId = $data['bodega_id']; + $stock = $data['stock']; + + // Verificar si ya existe la relación + if ($variante->bodegas()->where('bodega_id', $bodegaId)->exists()) { + Notification::make() + ->warning() + ->title('Variante ya asignada') + ->body('Esta variante ya está asignada a esa bodega. Use la opción de editar.') + ->send(); + return; + } + + // Crear la relación + $variante->bodegas()->attach($bodegaId, ['stock' => $stock]); + + Notification::make() + ->success() + ->title('Variante asignada') + ->body('La variante ha sido asignada a la bodega correctamente.') + ->send(); + }), + + Tables\Actions\Action::make('transferir_stock') + ->label('Transferir entre Bodegas') + ->icon('heroicon-o-arrows-right-left') + ->color('info') + ->form([ + Forms\Components\Placeholder::make('info') + ->label('Información de la Variante') + ->content(function () { + $variante = $this->getOwnerRecord(); + return "Variante: {$variante->sku} | Stock Total: {$variante->getStockEfectivo()} unidades"; + }), + + Forms\Components\Select::make('bodega_origen_id') + ->label('Bodega Origen') + ->options(function () { + $variante = $this->getOwnerRecord(); + return $variante->bodegas() + ->where('variante_bodega.stock', '>', 0) + ->pluck('nombre', 'bodegas.id'); + }) + ->required() + ->searchable() + ->reactive() + ->afterStateUpdated(function ($set, $get, $state) { + if ($state) { + $variante = $this->getOwnerRecord(); + $stock = $variante->bodegas() + ->where('bodegas.id', $state) + ->first()?->pivot?->stock ?? 0; + $set('stock_disponible', $stock); + } + }), + + Forms\Components\Placeholder::make('stock_disponible') + ->label('Stock Disponible en Origen') + ->content(fn($get) => ($get('stock_disponible') ?? 0) . ' unidades'), + + Forms\Components\Select::make('bodega_destino_id') + ->label('Bodega Destino') + ->options(Bodega::pluck('nombre', 'id')) + ->required() + ->searchable() + ->different('bodega_origen_id'), + + Forms\Components\TextInput::make('cantidad') + ->label('Cantidad a Transferir') + ->numeric() + ->required() + ->minValue(1) + ->maxValue(function ($get) { + return $get('stock_disponible') ?? 0; + }), + + Forms\Components\TextInput::make('motivo') + ->label('Motivo de la Transferencia') + ->placeholder('Ej: Reposición, reorganización de inventario...') + ->maxLength(255), + ]) + ->action(function (array $data): void { + $variante = $this->getOwnerRecord(); + $service = new TransferenciaBodegaService(); + + try { + $transferencia = $service->transferirVariante( + $variante->id, + $data['bodega_origen_id'], + $data['bodega_destino_id'], + $data['cantidad'], + $data['motivo'] ?? null + ); + + Notification::make() + ->success() + ->title('Transferencia Exitosa') + ->body("Se transfirieron {$data['cantidad']} unidades entre bodegas.") + ->send(); + } catch (\Exception $e) { + Notification::make() + ->danger() + ->title('Error en Transferencia') + ->body($e->getMessage()) + ->send(); + } + }), + ]) + ->actions([ + Tables\Actions\EditAction::make() + ->label('Editar Stock') + ->form([ + Forms\Components\TextInput::make('stock') + ->label('Stock en esta Bodega') + ->numeric() + ->required() + ->minValue(0) + ->helperText('Cantidad de esta variante en la bodega'), + ]) + ->fillForm(function ($record): array { + return [ + 'stock' => $record->pivot?->stock ?? 0, + ]; + }) + ->using(function (array $data, $record): void { + // Actualizamos el pivot directamente + $record->pivot->update(['stock' => (int)$data['stock']]); + + // Notificación + Notification::make() + ->success() + ->title('Stock Actualizado') + ->body("El stock se actualizó a {$data['stock']} unidades.") + ->send(); + }), + + Tables\Actions\Action::make('vaciar_stock') + ->label('Vaciar Stock') + ->icon('heroicon-o-minus-circle') + ->color('warning') + ->requiresConfirmation() + ->modalHeading('Vaciar Stock de Bodega') + ->modalDescription('¿Estás seguro de que quieres poner el stock en 0 para esta bodega? La bodega seguirá asignada a la variante.') + ->modalSubmitActionLabel('Sí, vaciar stock') + ->action(function ($record): void { + $record->pivot->update(['stock' => 0]); + + Notification::make() + ->success() + ->title('Stock Vaciado') + ->body('El stock de la bodega ha sido puesto en 0.') + ->send(); + }), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\BulkAction::make('vaciar_stock_multiple') + ->label('Vaciar Stock de Seleccionadas') + ->icon('heroicon-o-minus-circle') + ->color('warning') + ->requiresConfirmation() + ->modalHeading('Vaciar Stock de Bodegas Seleccionadas') + ->modalDescription('¿Estás seguro de que quieres poner el stock en 0 para todas las bodegas seleccionadas?') + ->action(function ($records): void { + foreach ($records as $record) { + $record->pivot->update(['stock' => 0]); + } + + Notification::make() + ->success() + ->title('Stock Vaciado') + ->body('El stock de las bodegas seleccionadas ha sido puesto en 0.') + ->send(); + }), + + Tables\Actions\DeleteBulkAction::make() + ->label('Quitar de Bodegas Seleccionadas') + ->requiresConfirmation() + ->modalHeading('Quitar Variante de Bodegas') + ->modalDescription('¿Estás seguro de que quieres quitar completamente esta variante de las bodegas seleccionadas? Se perderá toda la información de stock.') + ->modalSubmitActionLabel('Sí, quitar completamente'), + ]), + ]); + } +} diff --git a/app/Filament/Resources/ProductoResource.php b/app/Filament/Resources/ProductoResource.php new file mode 100644 index 0000000..48502f7 --- /dev/null +++ b/app/Filament/Resources/ProductoResource.php @@ -0,0 +1,658 @@ +user()->can('ver productos'); + } + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('nombre') + ->required() + ->maxLength(100), + // Campo para subir imagen + Forms\Components\FileUpload::make('imagen') + ->label('Imagen del Producto') + ->image() + ->directory(directory: 'productos') + ->maxSize(10240) + ->acceptedFileTypes(['image/jpeg', 'image/png', 'image/gif', 'image/webp']), + Forms\Components\Textarea::make('descripcion') + ->columnSpanFull() + ->required() + ->placeholder('Ingrese una descripción del producto') + ->default(''), + + TextInput::make('precio_compra') + ->required() + ->numeric() + ->maxLength(255) + ->placeholder('Ej: 1000') + ->lazy(), // Cambiar de reactive() a lazy() + + TextInput::make('precio_venta') + ->required() + ->numeric() + ->maxLength(255) + ->lazy() // Cambiar de reactive() a lazy() + ->placeholder('Ej: 1200') + ->afterStateUpdated(function (callable $get, callable $set) { + $precioCompra = $get('precio_compra'); + $precioVenta = $get('precio_venta'); + + // Solo validar si ambos valores están presentes y son significativos + if (!is_null($precioCompra) && !is_null($precioVenta) && + $precioCompra > 0 && $precioVenta > 0 && + $precioVenta < $precioCompra) { + Notification::make() + ->warning() + ->title('Advertencia') + ->body('El precio de venta es menor al precio de compra.') + ->persistent() + ->send(); + } + }), + + Forms\Components\TextInput::make('stock') + ->required() + ->numeric() + ->default(0) + ->lazy() // Cambiar de live() a lazy() + ->dehydrated() + ->hidden(fn($get, $record) => $record && $record->variants()->exists()) // Oculta si hay variantes + ->disabled(fn($get) => $get('producto_id') && \App\Models\Producto::find($get('producto_id'))->variants()->exists()) + ->visible(false) // Oculto - se maneja automáticamente + ->label('Stock (Unidades Base)'), + + Forms\Components\TextInput::make('stock_entrada') + ->label('Stock Inicial') + ->numeric() + ->default(0) + ->lazy() // Cambiar de live() a lazy() para evitar actualizaciones en tiempo real + ->dehydrated(true) // Permitir que se envíe al servidor + ->hidden(fn($get, $record) => $record && $record->variants()->exists()) + ->helperText(fn($get, $record) => $record && $record->variants()->exists() + ? 'El stock se maneja a nivel de variantes' + : 'Ingrese el stock inicial del producto') + ->afterStateUpdated(function (callable $get, callable $set) { + $stockEntrada = $get('stock_entrada') ?? 0; + $unidadMedida = $get('unidad_medida') ?? 'unidad'; + // Asegurar que la cantidad sea float (Filament a veces pasa strings desde inputs) + $stockEntradaFloat = is_numeric($stockEntrada) ? (float) $stockEntrada : 0.0; + $stockUnidades = Producto::convertirAUnidades($stockEntradaFloat, $unidadMedida); + $set('stock', $stockUnidades); + }) + ->hint(function (callable $get) { + $unidadMedida = $get('unidad_medida') ?? 'unidad'; + $factor = Producto::getFactorConversion($unidadMedida); + return $factor > 1 ? "Se convertirá automáticamente (×{$factor})" : null; + }), + + Forms\Components\TextInput::make('stock_minimo') + ->required() + ->numeric() + ->default(0) + ->lazy() // Cambiar de live() a lazy() + ->dehydrated() + ->visible(false) // Oculto - se maneja automáticamente + ->label('Stock Mínimo (Unidades Base)') + ->afterStateUpdated(function (callable $get, callable $set) { + $stockMinimo = $get('stock_minimo'); + $stockMaximo = $get('stock_maximo'); + + // Solo validar si hay valores significativos + if (!is_null($stockMinimo) && !is_null($stockMaximo) && + $stockMinimo > 0 && $stockMaximo > 0 && + $stockMaximo < $stockMinimo) { + Notification::make() + ->warning() + ->title('Advertencia') + ->body('El stock máximo debe ser mayor al stock mínimo.') + ->persistent() + ->send(); + } + }), + + Forms\Components\TextInput::make('stock_minimo_entrada') + ->label('Stock Mínimo') + ->numeric() + ->default(0) + ->lazy() // Cambiar de live() a lazy() para evitar actualizaciones en tiempo real + ->dehydrated(true) // Permitir que se envíe al servidor + ->hidden(fn($get, $record) => $record && $record->variants()->exists()) + ->helperText(fn($get, $record) => $record && $record->variants()->exists() + ? 'El stock mínimo se configura por variante' + : 'Configure el stock mínimo para alertas') + ->afterStateUpdated(function (callable $get, callable $set) { + $stockMinimoEntrada = $get('stock_minimo_entrada') ?? 0; + $unidadMedida = $get('unidad_medida') ?? 'unidad'; + $stockMinimoEntradaFloat = is_numeric($stockMinimoEntrada) ? (float) $stockMinimoEntrada : 0.0; + $stockMinimoUnidades = Producto::convertirAUnidades($stockMinimoEntradaFloat, $unidadMedida); + $set('stock_minimo', $stockMinimoUnidades); + + // Solo validar si hay un valor significativo para evitar notificaciones innecesarias + if ($stockMinimoEntradaFloat > 0) { + $stockMaximo = $get('stock_maximo'); + if (!is_null($stockMaximo) && $stockMaximo < $stockMinimoUnidades) { + Notification::make() + ->warning() + ->title('Advertencia') + ->body('El stock máximo debe ser mayor al stock mínimo.') + ->persistent() + ->send(); + } + } + }) + ->hint(function (callable $get) { + $unidadMedida = $get('unidad_medida') ?? 'unidad'; + $factor = Producto::getFactorConversion($unidadMedida); + return $factor > 1 ? "Se convertirá automáticamente (×{$factor})" : null; + }), + + Forms\Components\TextInput::make('stock_maximo') + ->required() + ->numeric() + ->default(0) + ->lazy() // Cambiar de live() a lazy() + ->dehydrated() + ->visible(false) // Oculto - se maneja automáticamente + ->label('Stock Máximo (Unidades Base)') + ->afterStateUpdated(function (callable $get, callable $set) { + $stockMinimo = $get('stock_minimo'); + $stockMaximo = $get('stock_maximo'); + + // Solo validar si hay valores significativos + if (!is_null($stockMinimo) && !is_null($stockMaximo) && + $stockMinimo > 0 && $stockMaximo > 0 && + $stockMaximo < $stockMinimo) { + Notification::make() + ->warning() + ->title('Advertencia') + ->body('El stock máximo debe ser mayor al stock mínimo.') + ->persistent() + ->send(); + } + }), + + Forms\Components\TextInput::make('stock_maximo_entrada') + ->label('Stock Máximo') + ->numeric() + ->default(function (callable $get) { + $unidadMedida = $get('unidad_medida') ?? 'unidad'; + return Producto::convertirDesdeUnidades(1000, $unidadMedida); + }) + ->lazy() // Cambiar de live() a lazy() para evitar actualizaciones en tiempo real + ->dehydrated(true) // Permitir que se envíe al servidor + ->hidden(fn($get, $record) => $record && $record->variants()->exists()) + ->helperText(fn($get, $record) => $record && $record->variants()->exists() + ? 'El stock máximo se configura por variante' + : 'Configure el stock máximo recomendado') + ->afterStateUpdated(function (callable $get, callable $set) { + $stockMaximoEntrada = $get('stock_maximo_entrada') ?? 0; + $unidadMedida = $get('unidad_medida') ?? 'unidad'; + $stockMaximoEntradaFloat = is_numeric($stockMaximoEntrada) ? (float) $stockMaximoEntrada : 0.0; + $stockMaximoUnidades = Producto::convertirAUnidades($stockMaximoEntradaFloat, $unidadMedida); + $set('stock_maximo', $stockMaximoUnidades); + + // Solo validar si hay un valor significativo para evitar notificaciones innecesarias + if ($stockMaximoEntradaFloat > 0) { + $stockMinimo = $get('stock_minimo'); + if (!is_null($stockMinimo) && $stockMaximoUnidades < $stockMinimo) { + Notification::make() + ->warning() + ->title('Advertencia') + ->body('El stock máximo debe ser mayor al stock mínimo.') + ->persistent() + ->send(); + } + } + }) + ->hint(function (callable $get) { + $unidadMedida = $get('unidad_medida') ?? 'unidad'; + $factor = Producto::getFactorConversion($unidadMedida); + return $factor > 1 ? "Se convertirá automáticamente (×{$factor})" : null; + }), + + Forms\Components\Select::make('unidad_medida') + ->label('Unidad de Medida') + ->options(Producto::getUnidadesMedida()) + ->default('unidad') + ->required() + ->live() + ->helperText('El sistema guardará todo en unidades individuales. Esta opción facilita la entrada de datos.') + ->afterStateUpdated(function (callable $get, callable $set) { + $unidad = $get('unidad_medida'); + $factor = Producto::getFactorConversion($unidad); + + // Actualizar los campos auxiliares basados en los valores actuales en unidades + $stockActual = $get('stock') ?? 0; + $stockMinimo = $get('stock_minimo') ?? 0; + $stockMaximo = $get('stock_maximo') ?? 1000; + + $set('stock_entrada', Producto::convertirDesdeUnidades($stockActual, $unidad)); + $set('stock_minimo_entrada', Producto::convertirDesdeUnidades($stockMinimo, $unidad)); + $set('stock_maximo_entrada', Producto::convertirDesdeUnidades($stockMaximo, $unidad)); + + if ($factor > 1) { + Notification::make() + ->info() + ->title('Conversión de Unidades') + ->body("1 {$unidad} = {$factor} unidades individuales") + ->send(); + } + }), + + Forms\Components\Select::make('categoria_id') + ->relationship('categoria', 'nombre') + ->searchable() + ->required() + ->lazy() // Cambiar de reactive() a lazy() + ->afterStateUpdated(fn($set, $get) => ProductoResource::updateSkuAndBarcode($set, $get)), + + TextInput::make('codigo_barras') + ->label('Código de Barras') + ->length(13) + ->lazy() // Cambiar de live() a lazy() + ->dehydrated() + ->hidden(fn($get, $record) => $record && $record->variants()->exists()) // Oculta si hay variantes + ->disabled(fn($get) => $get('producto_id') && \App\Models\Producto::find($get('producto_id'))->variants()->exists()) + ->suffixAction( + Action::make('imprimirQr') + ->icon('heroicon-o-printer') + ->color('primary') + ->hidden(fn($record) => is_null($record)) // Oculta el botón si no hay un registro + ->disabled(fn($get) => empty($get('codigo_barras'))) // Deshabilita si no hay código de barras + ->action(fn($state) => redirect()->route('imprimir.barcode', ['barcode' => $state])) // Redirige a la impresión + ->visible(fn($get, $record) => $record && !$record->variants()->exists()) // Muestra si el producto no tiene variantes + ), + + Forms\Components\Toggle::make('estado') + ->label('Estado') + ->default(true) + ->required(), + + Forms\Components\Hidden::make('producto_id') + ->default(fn($record) => $record->id ?? null), + Forms\Components\Hidden::make('categoria_id') + ->default(fn($record) => $record->categoria_id ?? null), + + ]); + } + + protected static function updateSkuAndBarcode($set, $get) + { + $countryCode = '57'; // Código de país + $categoryId = $get('categoria_id') ?? '00'; + + // Obtener el siguiente ID de producto + $nextProductId = Producto::max('id') + 1; + + $variantId = '00'; // Si no hay variante, usamos 00 + + // Generar código de barras estructurado + $eanService = app(\App\Services\EAN13Service::class); + $barcode = $eanService->generateUniqueBarcode($countryCode, $categoryId, $nextProductId, $variantId); + + // Asignar el código de barras al formulario + $set('codigo_barras', $barcode); + } + + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('nombre') + ->searchable(), + Tables\Columns\TextColumn::make('codigo_barras') + ->formatStateUsing(fn($record) => $record->variants()->exists() ? 'Tiene variantes' : $record->codigo_barras) + ->action(fn($record) => !$record->variants()->exists() ? redirect()->route('imprimir.barcode', ['barcode' => $record->codigo_barras]) : null) + ->tooltip(fn($record) => $record->variants()->exists() ? 'Este producto tiene variantes que contienen los Barcodes' : 'Imprimir código de barras'), + Tables\Columns\TextColumn::make('precio_compra') + ->searchable(), + Tables\Columns\TextColumn::make('precio_venta') + ->searchable(), + Tables\Columns\TextColumn::make('stock_total') + ->label('Stock') + ->getStateUsing(function ($record, \Livewire\Component $livewire) { + $filterState = $livewire->tableFilters ?? []; + $bodegaId = $filterState['bodegas']['value'] ?? null; + + if ($bodegaId) { + return $record->getStockTotalEnBodega($bodegaId); + } + + // Usar el método getStockEfectivo que considera bodegas, variantes y stock directo + return $record->getStockEfectivo(); + }) + ->formatStateUsing(function ($state, $record) { + $totalStockUnidades = $state; + $ok = $totalStockUnidades >= $record->stock_minimo; + $icon = $ok ? '✅' : '⚠️'; + + // Mostrar stock en la unidad de medida configurada + $unidadMedida = $record->unidad_medida ?? 'unidad'; + $stockEnUnidad = Producto::convertirDesdeUnidades($totalStockUnidades, $unidadMedida); + $nombreUnidad = Producto::getUnidadesMedida()[$unidadMedida] ?? 'Unidad (1)'; + + return "{$icon} {$stockEnUnidad} " . explode(' ', $nombreUnidad)[0]; + }) + ->tooltip(function ($record, \Livewire\Component $livewire) { + $filterState = $livewire->tableFilters ?? []; + $bodegaId = $filterState['bodegas']['value'] ?? null; + + if ($bodegaId) { + $totalStockUnidades = $record->getStockTotalEnBodega($bodegaId); + $bodegaNombre = \App\Models\Bodega::find($bodegaId)?->nombre ?? 'Bodega seleccionada'; + $origen = "\nEn {$bodegaNombre}"; + } else { + $totalStockUnidades = $record->getStockEfectivo(); + + $origen = ''; + if ($record->bodegas()->exists()) { + $origen = "\nDistribuido en " . $record->bodegas()->count() . " bodega(s)"; + } elseif ($record->variants()->exists()) { + $origen = "\nStock de variantes"; + } else { + $origen = "\nStock directo"; + } + } + + $unidadMedida = $record->unidad_medida ?? 'unidad'; + $stockEnUnidad = Producto::convertirDesdeUnidades($totalStockUnidades, $unidadMedida); + $nombreUnidad = Producto::getUnidadesMedida()[$unidadMedida] ?? 'Unidad (1)'; + + $mensaje = $totalStockUnidades < $record->stock_minimo + ? "Stock por debajo del mínimo" + : "Stock suficiente"; + + return "{$mensaje}\nStock en {$nombreUnidad}: {$stockEnUnidad}\nStock en unidades: {$totalStockUnidades}{$origen}"; + }), + + + Tables\Columns\TextColumn::make('stock_minimo') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('unidad_medida') + ->label('Unidad') + ->formatStateUsing(function ($state) { + $unidades = Producto::getUnidadesMedida(); + return explode(' ', $unidades[$state ?? 'unidad'])[0]; + }) + ->tooltip(function ($record) { + $unidades = Producto::getUnidadesMedida(); + return $unidades[$record->unidad_medida ?? 'unidad']; + }), + Tables\Columns\TextColumn::make('categoria.nombre') + ->searchable() + ->sortable(), + Tables\Columns\IconColumn::make('estado') + ->boolean(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + SelectFilter::make('categoria_id') + ->label('Categoría') + ->relationship('categoria', 'nombre') // Relación con el modelo Categoría + ->preload() // Precargar opciones + ->searchable(), // Permitir búsqueda en el filtro + SelectFilter::make('bodegas') + ->label('Bodega') + ->relationship('bodegas', 'nombre') + ->preload() + ->searchable(), + ]) + ->actions([ + Tables\Actions\EditAction::make(), + + Tables\Actions\DeleteAction::make() + ->before(function (Producto $record) { + // Verificar si el producto está siendo usado en compras + $comprasCount = $record->detalleCompras()->count(); + $ventasCount = $record->detalleVentas()->count(); + + if ($comprasCount > 0 || $ventasCount > 0) { + Notification::make() + ->warning() + ->title('No se puede eliminar') + ->body("Este producto está siendo usado en {$comprasCount} compras y {$ventasCount} ventas. Los registros se mantendrán con información histórica.") + ->persistent() + ->send(); + } + }), + + Tables\Actions\Action::make('transferir') + ->label('Transferir Stock') + ->icon('heroicon-o-arrow-path') + ->color('warning') + ->form([ + Forms\Components\Select::make('bodega_origen_id') + ->label('Bodega Origen') + ->options(function (Producto $record) { + return $record->bodegas() + ->wherePivot('stock', '>', 0) + ->pluck('nombre', 'bodegas.id'); + }) + ->required() + ->reactive() + ->helperText(function (callable $get, Producto $record) { + $bodegaId = $get('bodega_origen_id'); + if (!$bodegaId) return null; + + $bodega = $record->bodegas()->where('bodega_id', $bodegaId)->first(); + $stock = $bodega ? $bodega->pivot->stock : 0; + + return "Stock disponible: {$stock} unidades"; + }), + + Forms\Components\Select::make('bodega_destino_id') + ->label('Bodega Destino') + ->options(function (callable $get) { + $bodegaOrigenId = $get('bodega_origen_id'); + $bodegas = \App\Models\Bodega::all()->pluck('nombre', 'id'); + + if ($bodegaOrigenId) { + $bodegas = $bodegas->except($bodegaOrigenId); + } + + return $bodegas; + }) + ->required(), + + Forms\Components\TextInput::make('cantidad') + ->label('Cantidad') + ->numeric() + ->required() + ->minValue(1) + ->maxValue(function (callable $get, Producto $record) { + $bodegaId = $get('bodega_origen_id'); + if (!$bodegaId) return 999999; + + $bodega = $record->bodegas()->where('bodega_id', $bodegaId)->first(); + return $bodega ? $bodega->pivot->stock : 0; + }), + + Forms\Components\Textarea::make('motivo') + ->label('Motivo') + ->placeholder('Opcional') + ->rows(2), + ]) + ->action(function (Producto $record, array $data) { + try { + $service = new \App\Services\TransferenciaBodegaService(); + + $service->transferir( + $record->id, + $data['bodega_origen_id'], + $data['bodega_destino_id'], + $data['cantidad'], + $data['motivo'] ?? null + ); + + Notification::make() + ->title('Transferencia realizada') + ->body("Se transfirieron {$data['cantidad']} unidades de {$record->nombre}") + ->success() + ->send(); + + } catch (\Exception $e) { + Notification::make() + ->title('Error en transferencia') + ->body($e->getMessage()) + ->danger() + ->send(); + } + }) + ->visible(fn (Producto $record) => $record->bodegas()->wherePivot('stock', '>', 0)->exists()), + ]) + ->headerActions([ + Tables\Actions\Action::make('exportar') + ->label('Exportar a Excel') + ->icon('heroicon-o-arrow-down-tray') + ->color('success') + ->action(function () { + return Excel::download(new ProductosExport, 'productos_' . date('Y-m-d_H-i-s') . '.xlsx'); + }), + + Tables\Actions\Action::make('importar') + ->label('Importar desde Excel') + ->icon('heroicon-o-arrow-up-tray') + ->color('primary') + ->form([ + FileUpload::make('archivo') + ->label('Archivo Excel') + ->acceptedFileTypes([ + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'text/csv', + ]) + ->required() + ->helperText('Formatos aceptados: .xlsx, .xls, .csv') + ->disk('local') + ->directory('imports'), + ]) + ->action(function (array $data) { + try { + $import = new ProductosImport; + Excel::import($import, $data['archivo']); + + $failures = $import->failures(); + $errors = $import->errors(); + + if ($failures->isNotEmpty() || $errors->isNotEmpty()) { + $errorMessages = []; + + foreach ($failures as $failure) { + $errorMessages[] = "Fila {$failure->row()}: " . implode(', ', $failure->errors()); + } + + foreach ($errors as $error) { + $errorMessages[] = $error->getMessage(); + } + + Notification::make() + ->warning() + ->title('Importación completada con errores') + ->body('Algunos productos no se pudieron importar: ' . implode(' | ', array_slice($errorMessages, 0, 3))) + ->persistent() + ->send(); + } else { + Notification::make() + ->success() + ->title('Importación exitosa') + ->body('Los productos se importaron correctamente.') + ->send(); + } + + } catch (\Exception $e) { + Notification::make() + ->danger() + ->title('Error en la importación') + ->body('Ocurrió un error: ' . $e->getMessage()) + ->persistent() + ->send(); + } + }), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + + public static function getRelations(): array + { + return [ + VariantesRelationManager::class, + BodegasRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListProductos::route('/'), + 'create' => Pages\CreateProducto::route('/create'), + 'edit' => Pages\EditProducto::route('/{record}/edit'), + ]; + } + + public static function getNavigationBadgeColor(): ?string + { + return 'success'; // Verde para productos + } +} diff --git a/app/Filament/Resources/ProductoResource/Pages/CreateProducto.php b/app/Filament/Resources/ProductoResource/Pages/CreateProducto.php new file mode 100644 index 0000000..4341dd8 --- /dev/null +++ b/app/Filament/Resources/ProductoResource/Pages/CreateProducto.php @@ -0,0 +1,181 @@ + isset($data['stock_entrada']) ? $data['stock_entrada'] : 'NO PRESENTE', + 'stock_minimo_entrada' => isset($data['stock_minimo_entrada']) ? $data['stock_minimo_entrada'] : 'NO PRESENTE', + 'stock_maximo_entrada' => isset($data['stock_maximo_entrada']) ? $data['stock_maximo_entrada'] : 'NO PRESENTE', + ]); + + // Asegurar que descripcion no esté vacía + if (empty($data['descripcion']) || is_null($data['descripcion'])) { + $data['descripcion'] = 'Sin descripción'; + } + + // Procesar stock inicial + if (isset($data['stock_entrada'])) { + $stockEntrada = $data['stock_entrada']; + $unidadMedida = $data['unidad_medida'] ?? 'unidad'; + + // Convertir a unidades + $stockEntradaFloat = is_numeric($stockEntrada) ? (float) $stockEntrada : 0.0; + $data['stock'] = Producto::convertirAUnidades($stockEntradaFloat, $unidadMedida); + + Log::info('Stock procesado:', [ + 'stock_entrada' => $stockEntrada, + 'unidad_medida' => $unidadMedida, + 'stock_final' => $data['stock'] + ]); + } + + // Procesar stock mínimo + if (isset($data['stock_minimo_entrada'])) { + $stockMinimoEntrada = $data['stock_minimo_entrada']; + $unidadMedida = $data['unidad_medida'] ?? 'unidad'; + + // Convertir a unidades + $stockMinimoEntradaFloat = is_numeric($stockMinimoEntrada) ? (float) $stockMinimoEntrada : 0.0; + $data['stock_minimo'] = Producto::convertirAUnidades($stockMinimoEntradaFloat, $unidadMedida); + + Log::info('Stock mínimo procesado:', [ + 'stock_minimo_entrada' => $stockMinimoEntrada, + 'unidad_medida' => $unidadMedida, + 'stock_minimo_final' => $data['stock_minimo'] + ]); + } + + // Procesar stock máximo + if (isset($data['stock_maximo_entrada'])) { + $stockMaximoEntrada = $data['stock_maximo_entrada']; + $unidadMedida = $data['unidad_medida'] ?? 'unidad'; + + // Convertir a unidades + $stockMaximoEntradaFloat = is_numeric($stockMaximoEntrada) ? (float) $stockMaximoEntrada : 0.0; + $data['stock_maximo'] = Producto::convertirAUnidades($stockMaximoEntradaFloat, $unidadMedida); + + Log::info('Stock máximo procesado:', [ + 'stock_maximo_entrada' => $stockMaximoEntrada, + 'unidad_medida' => $unidadMedida, + 'stock_maximo_final' => $data['stock_maximo'] + ]); + } + + // Remover campos auxiliares que no deben guardarse + unset($data['stock_entrada'], $data['stock_minimo_entrada'], $data['stock_maximo_entrada']); + + Log::info('Datos finales para crear producto:', $data); + + return $data; + } + + protected function afterCreate(): void + { + $producto = $this->record; + + // Solo asignar stock a bodega principal si NO tiene variantes + if ($producto->stock > 0 && !$producto->variants()->exists()) { + try { + DB::beginTransaction(); + + // Buscar o crear la bodega principal + $bodegaPrincipal = Bodega::firstOrCreate([ + 'nombre' => 'Principal' + ]); + + Log::info("Asignando stock a bodega principal", [ + 'producto_id' => $producto->id, + 'producto_nombre' => $producto->nombre, + 'stock' => $producto->stock, + 'bodega_id' => $bodegaPrincipal->id, + 'bodega_nombre' => $bodegaPrincipal->nombre + ]); + + // Verificar si ya existe una relación con esta bodega + $existeRelacion = $producto->bodegas()->where('bodega_id', $bodegaPrincipal->id)->exists(); + + if (!$existeRelacion) { + // Asignar el stock a la bodega principal + $producto->bodegas()->attach($bodegaPrincipal->id, [ + 'stock' => $producto->stock + ]); + + Log::info("Stock asignado exitosamente a bodega principal"); + + // Mostrar notificación al usuario + Notification::make() + ->success() + ->title('Producto creado exitosamente') + ->body("Stock inicial de {$producto->stock} unidades asignado a la bodega Principal") + ->send(); + } else { + Log::info("El producto ya tiene relación con la bodega principal, actualizando stock"); + + // Actualizar el stock en la bodega principal + $producto->bodegas()->updateExistingPivot($bodegaPrincipal->id, [ + 'stock' => $producto->stock + ]); + + Notification::make() + ->success() + ->title('Producto creado exitosamente') + ->body("Stock actualizado en la bodega Principal: {$producto->stock} unidades") + ->send(); + } + + DB::commit(); + + } catch (\Exception $e) { + DB::rollback(); + + Log::error("Error al asignar stock a bodega principal", [ + 'producto_id' => $producto->id, + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + + // Mostrar notificación de error + Notification::make() + ->warning() + ->title('Producto creado con advertencia') + ->body('El producto se creó correctamente, pero hubo un problema al asignar el stock a la bodega principal.') + ->persistent() + ->send(); + } + } elseif ($producto->variants()->exists()) { + // Si tiene variantes, limpiar el stock del producto principal + $producto->update(['stock' => 0]); + + Log::info("Producto con variantes creado - stock principal establecido en 0", [ + 'producto_id' => $producto->id, + 'producto_nombre' => $producto->nombre + ]); + + Notification::make() + ->info() + ->title('Producto con variantes creado') + ->body('El stock se manejará a nivel de cada variante individual') + ->send(); + } + } +} diff --git a/app/Filament/Resources/ProductoResource/Pages/EditProducto.php b/app/Filament/Resources/ProductoResource/Pages/EditProducto.php new file mode 100644 index 0000000..62cc7cb --- /dev/null +++ b/app/Filament/Resources/ProductoResource/Pages/EditProducto.php @@ -0,0 +1,128 @@ + $data['stock'], + 'stock_entrada' => $data['stock_entrada'], + 'unidad_medida' => $unidadMedida + ]); + } + + // Convertir stock mínimo base a campo auxiliar + if (isset($data['stock_minimo'])) { + $data['stock_minimo_entrada'] = Producto::convertirDesdeUnidades($data['stock_minimo'], $unidadMedida); + Log::info('Stock mínimo convertido para edición:', [ + 'stock_minimo_base' => $data['stock_minimo'], + 'stock_minimo_entrada' => $data['stock_minimo_entrada'], + 'unidad_medida' => $unidadMedida + ]); + } + + // Convertir stock máximo base a campo auxiliar + if (isset($data['stock_maximo'])) { + $data['stock_maximo_entrada'] = Producto::convertirDesdeUnidades($data['stock_maximo'], $unidadMedida); + Log::info('Stock máximo convertido para edición:', [ + 'stock_maximo_base' => $data['stock_maximo'], + 'stock_maximo_entrada' => $data['stock_maximo_entrada'], + 'unidad_medida' => $unidadMedida + ]); + } + + Log::info('Datos finales para formulario de edición:', $data); + + return $data; + } + + protected function mutateFormDataBeforeSave(array $data): array + { + Log::info('Datos recibidos en EditProducto:', $data); + + // Asegurar que descripcion no esté vacía + if (empty($data['descripcion']) || is_null($data['descripcion'])) { + $data['descripcion'] = 'Sin descripción'; + } + + // Procesar stock inicial + if (isset($data['stock_entrada'])) { + $stockEntrada = $data['stock_entrada']; + $unidadMedida = $data['unidad_medida'] ?? 'unidad'; + + // Convertir a unidades + $stockEntradaFloat = is_numeric($stockEntrada) ? (float) $stockEntrada : 0.0; + $data['stock'] = Producto::convertirAUnidades($stockEntradaFloat, $unidadMedida); + + Log::info('Stock procesado:', [ + 'stock_entrada' => $stockEntrada, + 'unidad_medida' => $unidadMedida, + 'stock_final' => $data['stock'] + ]); + } + + // Procesar stock mínimo + if (isset($data['stock_minimo_entrada'])) { + $stockMinimoEntrada = $data['stock_minimo_entrada']; + $unidadMedida = $data['unidad_medida'] ?? 'unidad'; + + // Convertir a unidades + $stockMinimoEntradaFloat = is_numeric($stockMinimoEntrada) ? (float) $stockMinimoEntrada : 0.0; + $data['stock_minimo'] = Producto::convertirAUnidades($stockMinimoEntradaFloat, $unidadMedida); + + Log::info('Stock mínimo procesado:', [ + 'stock_minimo_entrada' => $stockMinimoEntrada, + 'unidad_medida' => $unidadMedida, + 'stock_minimo_final' => $data['stock_minimo'] + ]); + } + + // Procesar stock máximo + if (isset($data['stock_maximo_entrada'])) { + $stockMaximoEntrada = $data['stock_maximo_entrada']; + $unidadMedida = $data['unidad_medida'] ?? 'unidad'; + + // Convertir a unidades + $stockMaximoEntradaFloat = is_numeric($stockMaximoEntrada) ? (float) $stockMaximoEntrada : 0.0; + $data['stock_maximo'] = Producto::convertirAUnidades($stockMaximoEntradaFloat, $unidadMedida); + + Log::info('Stock máximo procesado:', [ + 'stock_maximo_entrada' => $stockMaximoEntrada, + 'unidad_medida' => $unidadMedida, + 'stock_maximo_final' => $data['stock_maximo'] + ]); + } + + // Remover campos auxiliares que no deben guardarse + unset($data['stock_entrada'], $data['stock_minimo_entrada'], $data['stock_maximo_entrada']); + + Log::info('Datos finales para editar producto:', $data); + + return $data; + } +} diff --git a/app/Filament/Resources/ProductoResource/Pages/ListProductos.php b/app/Filament/Resources/ProductoResource/Pages/ListProductos.php new file mode 100644 index 0000000..599859f --- /dev/null +++ b/app/Filament/Resources/ProductoResource/Pages/ListProductos.php @@ -0,0 +1,19 @@ +schema([ + Forms\Components\Select::make('bodega_id') + ->label('Bodega') + ->options(\App\Models\Bodega::pluck('nombre', 'id')) + ->required() + ->searchable() + ->preload(), + + Forms\Components\TextInput::make('stock') + ->label('Stock en esta Bodega') + ->numeric() + ->required() + ->default(0) + ->minValue(0) + ->helperText('Cantidad de este producto en la bodega seleccionada'), + ]); + } + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('nombre') + ->columns([ + Tables\Columns\TextColumn::make('nombre') + ->label('Bodega') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('pivot.stock') + ->label('Stock') + ->alignCenter() + ->sortable() + ->formatStateUsing(function ($state, $record) { + $producto = $this->getOwnerRecord(); + + // Validación defensiva + if (!$producto || !$producto->getKey()) { + return "Error: Producto no encontrado"; + } + + $unidadMedida = $producto->unidad_medida ?? 'unidad'; + $stockEnUnidad = Producto::convertirDesdeUnidades($state, $unidadMedida); + $nombreUnidad = explode(' ', Producto::getUnidadesMedida()[$unidadMedida])[0]; + + $estado = $state > 0 ? '✅' : '⚠️'; + return "{$estado} {$stockEnUnidad} {$nombreUnidad}"; + }) + ->tooltip(function ($state, $record) { + $producto = $this->getOwnerRecord(); + + // Validación defensiva + if (!$producto || !$producto->getKey()) { + return "Error: No se pudo cargar información del producto"; + } + + $unidadMedida = $producto->unidad_medida ?? 'unidad'; + $stockEnUnidad = Producto::convertirDesdeUnidades($state, $unidadMedida); + $nombreUnidad = Producto::getUnidadesMedida()[$unidadMedida]; + + return "Stock en {$nombreUnidad}: {$stockEnUnidad}\nStock en unidades: {$state}"; + }), + + Tables\Columns\TextColumn::make('pivot.updated_at') + ->label('Última Actualización') + ->dateTime('d/m/Y H:i') + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + Tables\Filters\Filter::make('con_stock') + ->label('Solo con Stock') + ->query(fn ($query) => $query->where('producto_bodega.stock', '>', 0)), + ]) + ->headerActions([ + Tables\Actions\CreateAction::make() + ->label('Asignar a Bodega') + ->modalHeading('Asignar Producto a Bodega') + ->mutateFormDataUsing(function (array $data): array { + // Asegurarse de que el bodega_id esté en el pivot + return $data; + }) + ->using(function (array $data): void { + $producto = $this->getOwnerRecord(); + + // Validación defensiva para evitar error getKey() on null + if (!$producto || !$producto->getKey()) { + Notification::make() + ->danger() + ->title('Error') + ->body('No se pudo obtener la información del producto.') + ->send(); + return; + } + + $bodegaId = $data['bodega_id']; + $stock = $data['stock']; + + // Verificar si ya existe la relación + if ($producto->bodegas()->where('bodega_id', $bodegaId)->exists()) { + Notification::make() + ->warning() + ->title('Producto ya asignado') + ->body('Este producto ya está asignado a esa bodega. Use la opción de editar.') + ->send(); + return; + } + + // Crear la relación + $producto->bodegas()->attach($bodegaId, ['stock' => $stock]); + + Notification::make() + ->success() + ->title('Producto asignado') + ->body('El producto ha sido asignado a la bodega correctamente.') + ->send(); + }), + + Tables\Actions\Action::make('distribuir_stock') + ->label('Distribuir Stock Total') + ->icon('heroicon-o-arrows-right-left') + ->color('warning') + ->form([ + Forms\Components\Placeholder::make('info') + ->label('Información') + ->content(function () { + $producto = $this->getOwnerRecord(); + + // Validación defensiva + if (!$producto || !$producto->getKey()) { + return "Error: No se pudo cargar información del producto"; + } + + $stockTotal = $producto->getStockEfectivo(); + $unidadMedida = $producto->unidad_medida ?? 'unidad'; + $stockEnUnidad = Producto::convertirDesdeUnidades($stockTotal, $unidadMedida); + $nombreUnidad = Producto::getUnidadesMedida()[$unidadMedida]; + + return "Stock total disponible: {$stockEnUnidad} {$nombreUnidad} ({$stockTotal} unidades)"; + }), + + Forms\Components\Repeater::make('distribucion') + ->label('Distribución por Bodega') + ->schema([ + Forms\Components\Select::make('bodega_id') + ->label('Bodega') + ->options(Bodega::pluck('nombre', 'id')) + ->required(), + + Forms\Components\TextInput::make('stock') + ->label('Stock a Asignar') + ->numeric() + ->required() + ->default(0) + ->minValue(0), + ]) + ->minItems(1) + ->addActionLabel('Añadir Bodega'), + ]) + ->action(function (array $data): void { + $producto = $this->getOwnerRecord(); + + // Validación defensiva + if (!$producto || !$producto->getKey()) { + Notification::make() + ->danger() + ->title('Error') + ->body('No se pudo obtener la información del producto.') + ->send(); + return; + } + + $distribucion = $data['distribucion'] ?? []; + + // Validar que la suma no exceda el stock total + $stockAsignado = array_sum(array_column($distribucion, 'stock')); + $stockTotal = $producto->getStockEfectivo(); + + if ($stockAsignado > $stockTotal) { + Notification::make() + ->danger() + ->title('Error de Distribución') + ->body("El stock asignado ({$stockAsignado}) excede el stock disponible ({$stockTotal})") + ->send(); + return; + } + + // Distribuir el stock + foreach ($distribucion as $item) { + $producto->bodegas()->syncWithoutDetaching([ + $item['bodega_id'] => ['stock' => $item['stock']] + ]); + } + + Notification::make() + ->success() + ->title('Stock Distribuido') + ->body('El stock ha sido distribuido correctamente entre las bodegas.') + ->send(); + }), + ]) + ->actions([ + Tables\Actions\EditAction::make() + ->label('Editar Stock') + ->form([ + Forms\Components\TextInput::make('stock') + ->label('Stock en esta Bodega') + ->numeric() + ->required() + ->minValue(0) + ->helperText('Cantidad de este producto en la bodega'), + ]) + ->fillForm(function ($record): array { + return [ + 'stock' => $record->pivot?->stock ?? 0, + ]; + }) + ->using(function (array $data, $record): void { + $record->pivot->update(['stock' => (int)$data['stock']]); + + Notification::make() + ->success() + ->title('Stock Actualizado') + ->body("El stock se actualizó a {$data['stock']} unidades.") + ->send(); + }), + + Tables\Actions\Action::make('vaciar_stock') + ->label('Vaciar Stock') + ->icon('heroicon-o-minus-circle') + ->color('warning') + ->requiresConfirmation() + ->modalHeading('Vaciar Stock de Bodega') + ->modalDescription('¿Estás seguro de que quieres poner el stock en 0 para esta bodega? La bodega seguirá asignada al producto.') + ->modalSubmitActionLabel('Sí, vaciar stock') + ->action(function ($record): void { + $record->pivot->update(['stock' => 0]); + + Notification::make() + ->success() + ->title('Stock Vaciado') + ->body('El stock de la bodega ha sido puesto en 0.') + ->send(); + }), +/* + Tables\Actions\DeleteAction::make() + ->label('Quitar Bodega') + ->requiresConfirmation() + ->modalHeading('Quitar Producto de Bodega') + ->modalDescription('¿Estás seguro de que quieres quitar completamente este producto de la bodega? Se perderá toda la información de stock.') + ->modalSubmitActionLabel('Sí, quitar completamente'), */ + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\BulkAction::make('vaciar_stock_multiple') + ->label('Vaciar Stock de Seleccionadas') + ->icon('heroicon-o-minus-circle') + ->color('warning') + ->requiresConfirmation() + ->modalHeading('Vaciar Stock de Bodegas Seleccionadas') + ->modalDescription('¿Estás seguro de que quieres poner el stock en 0 para todas las bodegas seleccionadas?') + ->action(function ($records): void { + foreach ($records as $record) { + $record->pivot->update(['stock' => 0]); + } + + Notification::make() + ->success() + ->title('Stock Vaciado') + ->body('El stock de las bodegas seleccionadas ha sido puesto en 0.') + ->send(); + }), + + Tables\Actions\DeleteBulkAction::make() + ->label('Quitar de Bodegas Seleccionadas') + ->requiresConfirmation() + ->modalHeading('Quitar Producto de Bodegas') + ->modalDescription('¿Estás seguro de que quieres quitar completamente este producto de las bodegas seleccionadas? Se perderá toda la información de stock.') + ->modalSubmitActionLabel('Sí, quitar completamente'), + ]), + ]); + } +} \ No newline at end of file diff --git a/app/Filament/Resources/ProductoResource/RelationManagers/VariantesRelationManager.php b/app/Filament/Resources/ProductoResource/RelationManagers/VariantesRelationManager.php new file mode 100644 index 0000000..2581d70 --- /dev/null +++ b/app/Filament/Resources/ProductoResource/RelationManagers/VariantesRelationManager.php @@ -0,0 +1,411 @@ +schema([ + Forms\Components\Section::make('Información de la Variante') + ->schema([ + Forms\Components\Select::make('color_id') + ->relationship('color', 'name') + ->searchable() + ->required() + ->reactive() + ->afterStateUpdated(fn($set, $get, $component) => $this->updateSkuAndBarcode($set, $get, $component)), + + Forms\Components\Select::make('size_id') + ->relationship('size', 'name') + ->searchable() + ->required() + ->reactive() + ->afterStateUpdated(fn($set, $get, $component) => $this->updateSkuAndBarcode($set, $get, $component)), + + Forms\Components\TextInput::make('stock') + ->label('Stock Inicial') + ->required() + ->numeric() + ->default(0) + ->helperText('Este será el stock inicial que se asignará a la bodega seleccionada'), + + Forms\Components\TextInput::make('sku') + ->label('SKU') + ->required() + ->maxLength(50) + ->dehydrated(), // Se guarda en la base de datos + + TextInput::make('barcode') + ->label('Código de Barras') + ->required() + ->length(13) + ->dehydrated() + ->suffixAction( + Action::make('imprimirQr') + ->icon('heroicon-o-printer') + ->color('primary') + ->hidden(fn($record) => is_null($record)) + ->action(fn($state) => redirect()->route('imprimir.barcode', ['barcode' => $state])) + ->hidden(fn($record) => is_null($record)) + ) + ]) + ->columns(2), + + Forms\Components\Section::make('Asignación de Bodega') + ->schema([ + Forms\Components\Select::make('bodega_id') + ->label('Bodega Inicial') + ->options(Bodega::pluck('nombre', 'id')) + ->required() + ->searchable() + ->preload() + ->default(function () { + // Intentar obtener la bodega principal como default + $bodegaPrincipal = Bodega::where('nombre', 'Principal')->first(); + return $bodegaPrincipal?->id; + }) + ->helperText('Seleccione la bodega donde se asignará el stock inicial de esta variante'), + + Forms\Components\Placeholder::make('info_bodega') + ->label('Información') + ->content('La variante se creará con el stock especificado en la bodega seleccionada. Podrá distribuir a otras bodegas posteriormente.') + ]) + ->columns(1), + ]); + } + + + protected static function updateSkuAndBarcode($set, $get, $component) + { + $producto = $component->getLivewire()->ownerRecord; + $color = $get('color_id') ? \App\Models\Color::find($get('color_id')) : null; + $size = $get('size_id') ? \App\Models\Size::find($get('size_id')) : null; + + $exists = ProductVariant::where('producto_id', $get('producto_id')) + ->where('color_id', $get('color_id')) + ->where('size_id', $get('size_id')) + ->exists(); + + if ($exists) { + // Mostrar notificación en Filament + Notification::make() + ->title('Error') + ->body('Esta combinación de producto, color y talla ya existe.') + ->danger() + ->send(); + } + // Generar SKU basado en el producto, color y talla + $baseSku = strtoupper(substr($producto?->nombre ?? 'XX', 0, 2)) . '-' . + strtoupper(substr($color?->name ?? 'XX', 0, 2)) . '-' . + strtoupper(substr($size?->name ?? 'XX', 0, 2)); + + // Asegurar SKU único + $sku = $baseSku; + $counter = 1; + while (ProductVariant::where('sku', $sku)->exists()) { + $sku = $baseSku . '-' . $counter; + $counter++; + } + + // Obtener datos para el código de barras + $countryCode = '57'; // Código de país (puedes cambiarlo) + $categoryId = $producto?->categoria_id ?? 00; + $productId = $producto?->id ?? 00000; + $variantId = ProductVariant::where('producto_id',$productId)->count() ?? 0; + $variantId += 1; + + // Generar código de barras estructurado + $eanService = app(\App\Services\EAN13Service::class); + $barcode = $eanService->generateUniqueBarcode($countryCode, $categoryId, $productId, $variantId); + + // Asignar valores al formulario + $set('sku', $sku); + $set('barcode', $barcode); + } + + /** + * Generar SKU y código de barras únicos para una variante + */ + private function generateUniqueSkuAndBarcode(ProductVariant $variante): void + { + $producto = $variante->producto; + $color = $variante->color; + $size = $variante->size; + + // Generar SKU + $baseSku = strtoupper(substr($producto->nombre ?? 'XX', 0, 2)) . '-' . + strtoupper(substr($color->name ?? 'XX', 0, 2)) . '-' . + strtoupper(substr($size->name ?? 'XX', 0, 2)); + + $sku = $baseSku; + $counter = 1; + while (ProductVariant::where('sku', $sku)->exists()) { + $sku = $baseSku . '-' . $counter; + $counter++; + } + + // Generar código de barras + $countryCode = '57'; + $categoryId = $producto->categoria_id ?? 00; + $productId = $producto->id ?? 00000; + $variantId = ProductVariant::where('producto_id', $producto->id)->count() + 1; + + $eanService = app(\App\Services\EAN13Service::class); + $barcode = $eanService->generateUniqueBarcode($countryCode, $categoryId, $productId, $variantId); + + $variante->sku = $sku; + $variante->barcode = $barcode; + } + + + + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('sku') + ->columns([ + Tables\Columns\TextColumn::make('sku') + ->label('SKU') + ->searchable() + ->sortable(), + + Tables\Columns\TextColumn::make('color.name') + ->label('Color') + ->badge() + ->color('info'), + + Tables\Columns\TextColumn::make('size.name') + ->label('Talla') + ->badge() + ->color('warning'), + + Tables\Columns\TextColumn::make('stock') + ->label('Stock Directo') + ->numeric() + ->sortable() + ->tooltip('Stock directo de la variante (sin considerar bodegas)'), + + Tables\Columns\TextColumn::make('stock_efectivo') + ->label('Stock Total') + ->getStateUsing(function ($record) { + return $record->getStockEfectivo(); + }) + ->badge() + ->color(fn ($state) => $state > 0 ? 'success' : 'danger') + ->tooltip('Stock total considerando todas las bodegas'), + + Tables\Columns\TextColumn::make('bodegas_info') + ->label('Distribución en Bodegas') + ->getStateUsing(function ($record) { + $bodegas = $record->bodegas()->get(); + if ($bodegas->count() === 0) { + return 'Sin asignar a bodegas'; + } + + $distribucion = $bodegas->map(function ($bodega) { + return "{$bodega->nombre}: {$bodega->pivot->stock}"; + })->join(' | '); + + return $distribucion; + }) + ->wrap() + ->tooltip('Distribución de stock por bodega'), + + Tables\Columns\TextColumn::make('barcode') + ->label('Código de Barras') + ->action(fn($record) => redirect()->route('imprimir.barcode', ['barcode' => $record->barcode])) + ->tooltip('Click para imprimir código QR') + ->copyable() + ->copyMessage('Código copiado') + ->toggleable(isToggledHiddenByDefault: true), + ]) + + ->filters([ + Tables\Filters\SelectFilter::make('color_id') + ->label('Color') + ->relationship('color', 'name') + ->searchable(), + + Tables\Filters\SelectFilter::make('size_id') + ->label('Talla') + ->relationship('size', 'name') + ->searchable(), + + Tables\Filters\Filter::make('con_stock') + ->label('Con Stock') + ->query(fn (Builder $query): Builder => + $query->where('stock', '>', 0) + ->orWhereHas('bodegas', function ($q) { + $q->where('variante_bodega.stock', '>', 0); + }) + ), + + Tables\Filters\Filter::make('sin_stock') + ->label('Sin Stock') + ->query(fn (Builder $query): Builder => + $query->where('stock', '=', 0) + ->whereDoesntHave('bodegas', function ($q) { + $q->where('variante_bodega.stock', '>', 0); + }) + ), + + Tables\Filters\SelectFilter::make('bodega_id') + ->label('En Bodega') + ->options(Bodega::pluck('nombre', 'id')) + ->query(function (Builder $query, array $data): Builder { + return $query->when( + $data['value'], + fn (Builder $query, $value): Builder => $query->whereHas('bodegas', function ($q) use ($value) { + $q->where('bodegas.id', $value); + }) + ); + }), + ]) + ->headerActions([ + Tables\Actions\CreateAction::make() + ->label('Crear Variante') + ->modalHeading('Crear Nueva Variante') + ->modalDescription('Complete la información de la variante y seleccione la bodega inicial') + ->modalWidth('3xl') + ->using(function (array $data, string $model): ProductVariant { + // Extraer bodega_id de los datos antes de crear la variante + $bodegaId = $data['bodega_id']; + $stockInicial = $data['stock']; + + // Remover bodega_id de los datos para evitar errores en la creación + unset($data['bodega_id']); + + // Crear la variante + $variante = $this->getOwnerRecord()->variants()->create($data); + + // Asignar a la bodega seleccionada + if ($bodegaId && $stockInicial > 0) { + $variante->bodegas()->attach($bodegaId, ['stock' => $stockInicial]); + + $bodegaNombre = Bodega::find($bodegaId)->nombre; + Notification::make() + ->success() + ->title('Variante creada exitosamente') + ->body("La variante {$variante->sku} se creó con {$stockInicial} unidades en la bodega {$bodegaNombre}") + ->send(); + } else if ($bodegaId) { + // Si no hay stock inicial pero se seleccionó bodega, crear la relación con stock 0 + $variante->bodegas()->attach($bodegaId, ['stock' => 0]); + + $bodegaNombre = Bodega::find($bodegaId)->nombre; + Notification::make() + ->success() + ->title('Variante creada') + ->body("La variante {$variante->sku} se creó y asignó a la bodega {$bodegaNombre}") + ->send(); + } + + return $variante; + }), + ]) + ->actions([ + Tables\Actions\EditAction::make() + ->label('Editar') + ->modalWidth('3xl'), + + Tables\Actions\Action::make('gestionar_bodegas') + ->label('Gestionar Bodegas') + ->icon('heroicon-o-building-storefront') + ->color('info') + ->url(fn (ProductVariant $record): string => + "/admin/product-variants/{$record->id}/edit" + ) + ->openUrlInNewTab() + ->tooltip('Abrir gestión completa de bodegas para esta variante'), + + Tables\Actions\Action::make('duplicar_variante') + ->label('Duplicar') + ->icon('heroicon-o-document-duplicate') + ->color('warning') + ->form([ + Forms\Components\Select::make('color_id') + ->label('Nuevo Color') + ->relationship('color', 'name') + ->required(), + Forms\Components\Select::make('size_id') + ->label('Nueva Talla') + ->relationship('size', 'name') + ->required(), + Forms\Components\TextInput::make('stock_inicial') + ->label('Stock Inicial') + ->numeric() + ->default(0), + Forms\Components\Select::make('bodega_id') + ->label('Bodega Inicial') + ->options(Bodega::pluck('nombre', 'id')) + ->required(), + ]) + ->action(function (ProductVariant $record, array $data): void { + // Verificar que no exista la combinación + $exists = ProductVariant::where('producto_id', $record->producto_id) + ->where('color_id', $data['color_id']) + ->where('size_id', $data['size_id']) + ->exists(); + + if ($exists) { + Notification::make() + ->danger() + ->title('Error') + ->body('Ya existe una variante con esa combinación de color y talla') + ->send(); + return; + } + + // Crear nueva variante + $newVariant = $record->replicate([ + 'sku', 'barcode', 'color_id', 'size_id' + ]); + $newVariant->color_id = $data['color_id']; + $newVariant->size_id = $data['size_id']; + $newVariant->stock = $data['stock_inicial']; + + // Generar SKU y código de barras únicos + $this->generateUniqueSkuAndBarcode($newVariant); + $newVariant->save(); + + // Asignar a bodega + if ($data['bodega_id'] && $data['stock_inicial'] > 0) { + $newVariant->bodegas()->attach($data['bodega_id'], ['stock' => $data['stock_inicial']]); + } + + Notification::make() + ->success() + ->title('Variante duplicada') + ->body("Nueva variante {$newVariant->sku} creada exitosamente") + ->send(); + }), + + Tables\Actions\DeleteAction::make() + ->label('Eliminar'), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } +} diff --git a/app/Filament/Resources/ProveedorResource.php b/app/Filament/Resources/ProveedorResource.php new file mode 100644 index 0000000..b5b5c2a --- /dev/null +++ b/app/Filament/Resources/ProveedorResource.php @@ -0,0 +1,98 @@ +user()->can('ver proveedores'); + } + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('nombre') + ->required() + ->maxLength(255), + Forms\Components\TextInput::make('contacto') + ->maxLength(255), + Forms\Components\TextInput::make('telefono') + ->tel() + ->maxLength(20), + Forms\Components\TextInput::make('correo') + ->maxLength(255), + Forms\Components\Textarea::make('direccion') + ->columnSpanFull(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('nombre') + ->searchable(), + Tables\Columns\TextColumn::make('contacto') + ->searchable(), + Tables\Columns\TextColumn::make('telefono') + ->searchable(), + Tables\Columns\TextColumn::make('correo') + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListProveedors::route('/'), + 'create' => Pages\CreateProveedor::route('/create'), + 'edit' => Pages\EditProveedor::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/ProveedorResource/Pages/CreateProveedor.php b/app/Filament/Resources/ProveedorResource/Pages/CreateProveedor.php new file mode 100644 index 0000000..33bd00e --- /dev/null +++ b/app/Filament/Resources/ProveedorResource/Pages/CreateProveedor.php @@ -0,0 +1,12 @@ +user()->can('ver reportes'); + } + + public ?string $fromDate = null; + public ?string $toDate = null; + public ?string $email = null; + + public function generateReport() + { + $this->validate([ + 'fromDate' => 'required|date', + 'toDate' => 'required|date|after_or_equal:fromDate', + 'email' => 'required|email', // Validar que el campo 'email' sea una dirección de correo válida + ]); + + $email = $this->email; // El correo electrónico del formulario + + // Obtener las ventas dentro del rango de fechas + $ventas = Venta::with(['cliente', 'detalles.producto', 'detalles.variante']) + ->whereBetween('created_at', [$this->fromDate, $this->toDate]) + ->get(); + + // Enviar el correo con el reporte de ventas + Mail::to($email)->send(new ReporteVentasMail($ventas, $this->fromDate, $this->toDate, $email)); + + // Restablecer los campos a null después de enviar el correo + $this->fromDate = null; + $this->toDate = null; + $this->email = null; + + // Mostrar mensaje de éxito + session()->flash('success', 'Reporte enviado al correo.'); + } +} diff --git a/app/Filament/Resources/RoleResource.php b/app/Filament/Resources/RoleResource.php new file mode 100644 index 0000000..6fa2047 --- /dev/null +++ b/app/Filament/Resources/RoleResource.php @@ -0,0 +1,94 @@ +user()->can('ver roles'); + } + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('name') + ->label('Nombre del Rol') + ->required() + ->unique(ignoreRecord: true) + ->maxLength(255), + + Forms\Components\MultiSelect::make('permissions') + ->label('Permisos') + ->relationship('permissions', 'name') + ->options(Permission::pluck('name', 'id')) + ->searchable() + ->preload() + ->columnSpanFull(), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('id')->sortable(), + Tables\Columns\TextColumn::make('name') + ->label('Rol') + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('permissions.name') + ->label('Permisos') + ->badge() + ->separator(', '), + Tables\Columns\TextColumn::make('created_at') + ->label('Creado el') + ->dateTime('d/m/Y H:i') + ->sortable(), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make()->visible(fn($record) => $record->name !== 'Super Admin'), + Tables\Actions\DeleteAction::make()->visible(fn($record) => $record->name !== 'Super Admin'), + ]) + ->bulkActions([ + Tables\Actions\DeleteBulkAction::make(), + ]); + } + + public static function getRelations(): array + { + return []; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListRoles::route('/'), + 'create' => Pages\CreateRole::route('/create'), + 'edit' => Pages\EditRole::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/RoleResource/Pages/CreateRole.php b/app/Filament/Resources/RoleResource/Pages/CreateRole.php new file mode 100644 index 0000000..ee86d43 --- /dev/null +++ b/app/Filament/Resources/RoleResource/Pages/CreateRole.php @@ -0,0 +1,12 @@ +user()->can('ver sizes'); + } + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('name') + ->required() + ->maxLength(10), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('name') + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListSizes::route('/'), + 'create' => Pages\CreateSize::route('/create'), + 'edit' => Pages\EditSize::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/SizeResource/Pages/CreateSize.php b/app/Filament/Resources/SizeResource/Pages/CreateSize.php new file mode 100644 index 0000000..19293e3 --- /dev/null +++ b/app/Filament/Resources/SizeResource/Pages/CreateSize.php @@ -0,0 +1,12 @@ +schema([ + Forms\Components\Section::make('Información del Producto') + ->schema([ + Forms\Components\Select::make('producto_id') + ->label('Producto') + ->relationship('producto', 'nombre') + ->searchable() + ->preload() + ->required() + ->reactive() + ->afterStateUpdated(function ($set, $get, $state) { + if ($state) { + $producto = Producto::find($state); + if ($producto && $producto->variants()->exists()) { + $set('tiene_variantes', true); + $set('variante_id', null); // Limpiar selección anterior + $set('stock_disponible_info', null); + // Mostrar información sobre las variantes + $cantidadVariantes = $producto->variants()->count(); + $set('info_variantes', "Este producto tiene {$cantidadVariantes} variante(s). Debe seleccionar una variante específica para la transferencia."); + } else { + $set('tiene_variantes', false); + $set('variante_id', null); + $set('info_variantes', null); + // Mostrar stock disponible del producto + $stockTotal = $producto->getStockEfectivo(); + $set('stock_disponible_info', "Stock total del producto: {$stockTotal} unidades"); + } + } else { + $set('tiene_variantes', false); + $set('variante_id', null); + $set('info_variantes', null); + $set('stock_disponible_info', null); + } + }), + + Forms\Components\Placeholder::make('info_variantes') + ->label('Información del Producto') + ->content(fn ($get) => $get('info_variantes') ?? '') + ->visible(fn ($get) => $get('tiene_variantes')), + + Forms\Components\Placeholder::make('stock_disponible_info') + ->label('Stock Disponible') + ->content(fn ($get) => $get('stock_disponible_info') ?? '') + ->visible(fn ($get) => !$get('tiene_variantes') && $get('stock_disponible_info')), + + Forms\Components\Select::make('variante_id') + ->label('Seleccionar Variante') + ->options(function ($get) { + $productoId = $get('producto_id'); + if ($productoId) { + return ProductVariant::where('producto_id', $productoId) + ->with(['color', 'size']) + ->get() + ->mapWithKeys(function ($variante) { + $colorName = $variante->color->name ?? ''; + $sizeName = $variante->size->name ?? ''; + $stockEfectivo = $variante->getStockEfectivo(); + $displayName = "{$variante->sku} - {$colorName} {$sizeName} (Stock: {$stockEfectivo})"; + return [$variante->id => $displayName]; + }); + } + return []; + }) + ->searchable() + ->required(fn ($get) => $get('tiene_variantes')) + ->visible(fn ($get) => $get('tiene_variantes')) + ->reactive() + ->afterStateUpdated(function ($set, $get, $state) { + if ($state) { + $variante = ProductVariant::find($state); + if ($variante) { + $stockTotal = $variante->getStockEfectivo(); + $set('stock_variante_info', "Stock total de esta variante: {$stockTotal} unidades"); + } + } else { + $set('stock_variante_info', null); + } + }) + ->helperText('Seleccione la variante específica que desea transferir'), + + Forms\Components\Placeholder::make('stock_variante_info') + ->label('Stock de la Variante') + ->content(fn ($get) => $get('stock_variante_info') ?? '') + ->visible(fn ($get) => $get('tiene_variantes') && $get('variante_id') && $get('stock_variante_info')), + ]) + ->columns(2), + + Forms\Components\Section::make('Detalles de la Transferencia') + ->schema([ + Forms\Components\Select::make('bodega_origen_id') + ->label('Bodega Origen') + ->options(function ($get) { + $productoId = $get('producto_id'); + $varianteId = $get('variante_id'); + + if ($varianteId) { + // Si hay variante seleccionada, mostrar solo bodegas con stock de esa variante + $variante = ProductVariant::find($varianteId); + if ($variante) { + return $variante->bodegas() + ->where('variante_bodega.stock', '>', 0) + ->get() + ->mapWithKeys(function ($bodega) { + return [$bodega->id => "{$bodega->nombre} (Stock: {$bodega->pivot->stock})"]; + }); + } + } elseif ($productoId) { + // Si hay producto sin variantes, mostrar bodegas con stock del producto + $producto = Producto::find($productoId); + if ($producto && !$producto->variants()->exists()) { + return $producto->bodegas() + ->where('producto_bodega.stock', '>', 0) + ->get() + ->mapWithKeys(function ($bodega) { + return [$bodega->id => "{$bodega->nombre} (Stock: {$bodega->pivot->stock})"]; + }); + } + } + + // Fallback: mostrar todas las bodegas + return Bodega::pluck('nombre', 'id'); + }) + ->searchable() + ->required() + ->reactive() + ->afterStateUpdated(function ($set, $get, $state) { + $set('stock_origen_disponible', null); + if ($state) { + $productoId = $get('producto_id'); + $varianteId = $get('variante_id'); + + if ($varianteId) { + $variante = ProductVariant::find($varianteId); + $stock = $variante->bodegas() + ->where('bodega_id', $state) + ->first()?->pivot?->stock ?? 0; + } elseif ($productoId) { + $producto = Producto::find($productoId); + $stock = $producto->bodegas() + ->where('bodega_id', $state) + ->first()?->pivot?->stock ?? 0; + } else { + $stock = 0; + } + + $bodegaNombre = Bodega::find($state)?->nombre ?? ''; + $set('stock_origen_disponible', "Stock disponible en {$bodegaNombre}: {$stock} unidades"); + $set('max_cantidad', $stock); + } + }) + ->helperText('Solo se muestran bodegas con stock disponible'), + + Forms\Components\Placeholder::make('stock_origen_disponible') + ->label('Stock en Bodega Origen') + ->content(fn ($get) => $get('stock_origen_disponible') ?? '') + ->visible(fn ($get) => $get('stock_origen_disponible')), + + Forms\Components\Select::make('bodega_destino_id') + ->label('Bodega Destino') + ->relationship('bodegaDestino', 'nombre') + ->searchable() + ->required() + ->different('bodega_origen_id'), + + Forms\Components\TextInput::make('cantidad') + ->label('Cantidad a Transferir') + ->numeric() + ->required() + ->minValue(1) + ->maxValue(fn ($get) => $get('max_cantidad') ?? 999999) + ->helperText(fn ($get) => + $get('max_cantidad') ? "Máximo disponible: {$get('max_cantidad')} unidades" : '' + ), + + Forms\Components\Textarea::make('motivo') + ->label('Motivo de la Transferencia') + ->placeholder('Ej: Reposición de sucursal, reorganización de inventario...') + ->rows(3) + ->columnSpanFull(), + ]) + ->columns(2), + + Forms\Components\Hidden::make('usuario_id') + ->default(Auth::id()), + + Forms\Components\Hidden::make('fecha_transferencia') + ->default(now()), + + Forms\Components\Hidden::make('tiene_variantes') + ->default(false), + + Forms\Components\Hidden::make('max_cantidad') + ->default(0), + + Forms\Components\Hidden::make('info_variantes'), + Forms\Components\Hidden::make('stock_disponible_info'), + Forms\Components\Hidden::make('stock_variante_info'), + Forms\Components\Hidden::make('stock_origen_disponible'), + ]); + } + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('producto.nombre') + ->label('Producto') + ->searchable() + ->sortable() + ->wrap(), + + Tables\Columns\TextColumn::make('variante_info') + ->label('Variante') + ->getStateUsing(function ($record) { + if ($record->variante_id) { + $variante = ProductVariant::find($record->variante_id); + if ($variante) { + $colorName = $variante->color->name ?? ''; + $sizeName = $variante->size->name ?? ''; + return "{$variante->sku} - {$colorName} {$sizeName}"; + } + } + return 'Producto general'; + }) + ->badge() + ->color(fn ($state) => $state === 'Producto general' ? 'info' : 'warning') + ->searchable(query: function (Builder $query, string $search): Builder { + return $query->whereHas('producto.variants', function ($q) use ($search) { + $q->where('sku', 'like', "%{$search}%"); + }); + }), + + Tables\Columns\TextColumn::make('bodegaOrigen.nombre') + ->label('Bodega Origen') + ->badge() + ->color('danger') + ->sortable(), + + Tables\Columns\TextColumn::make('bodegaDestino.nombre') + ->label('Bodega Destino') + ->badge() + ->color('success') + ->sortable(), + + Tables\Columns\TextColumn::make('cantidad') + ->label('Cantidad') + ->numeric() + ->sortable() + ->badge() + ->color('primary'), + + Tables\Columns\TextColumn::make('motivo') + ->label('Motivo') + ->limit(30) + ->tooltip(function ($record) { + return $record->motivo; + }) + ->wrap(), + + Tables\Columns\TextColumn::make('usuario.name') + ->label('Usuario') + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + + Tables\Columns\TextColumn::make('fecha_transferencia') + ->label('Fecha') + ->dateTime('d/m/Y H:i') + ->sortable() + ->badge() + ->color('gray'), + + Tables\Columns\TextColumn::make('created_at') + ->label('Creado') + ->dateTime('d/m/Y H:i') + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->filters([ + SelectFilter::make('bodega_origen_id') + ->label('Bodega Origen') + ->relationship('bodegaOrigen', 'nombre'), + + SelectFilter::make('bodega_destino_id') + ->label('Bodega Destino') + ->relationship('bodegaDestino', 'nombre'), + + SelectFilter::make('producto_id') + ->label('Producto') + ->relationship('producto', 'nombre') + ->searchable(), + + Tables\Filters\Filter::make('con_variantes') + ->label('Solo Variantes') + ->query(fn (Builder $query): Builder => $query->whereNotNull('variante_id')), + + Tables\Filters\Filter::make('sin_variantes') + ->label('Solo Productos Generales') + ->query(fn (Builder $query): Builder => $query->whereNull('variante_id')), + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + // + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListTransferenciaBodegas::route('/'), + 'create' => Pages\CreateTransferenciaBodega::route('/create'), + 'edit' => Pages\EditTransferenciaBodega::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/TransferenciaBodegaResource/Pages/CreateTransferenciaBodega.php b/app/Filament/Resources/TransferenciaBodegaResource/Pages/CreateTransferenciaBodega.php new file mode 100644 index 0000000..0d29509 --- /dev/null +++ b/app/Filament/Resources/TransferenciaBodegaResource/Pages/CreateTransferenciaBodega.php @@ -0,0 +1,57 @@ +transferirVariante( + $data['variante_id'], + $data['bodega_origen_id'], + $data['bodega_destino_id'], + $data['cantidad'], + $data['motivo'] ?? null + ); + } else { + // Transferencia de producto + $transferencia = $transferenciaBodegaService->transferir( + $data['producto_id'], + $data['bodega_origen_id'], + $data['bodega_destino_id'], + $data['cantidad'], + $data['motivo'] ?? null + ); + } + + Notification::make() + ->title('Transferencia completada exitosamente') + ->success() + ->send(); + + return $transferencia; + + } catch (\Exception $e) { + Notification::make() + ->title('Error en la transferencia') + ->body($e->getMessage()) + ->danger() + ->send(); + + throw $e; + } + } +} diff --git a/app/Filament/Resources/TransferenciaBodegaResource/Pages/EditTransferenciaBodega.php b/app/Filament/Resources/TransferenciaBodegaResource/Pages/EditTransferenciaBodega.php new file mode 100644 index 0000000..669af5a --- /dev/null +++ b/app/Filament/Resources/TransferenciaBodegaResource/Pages/EditTransferenciaBodega.php @@ -0,0 +1,19 @@ +user()->can('ver usuarios'); + } + + + protected static ?string $navigationIcon = 'heroicon-o-user'; + + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\TextInput::make('name') + ->required() + ->maxLength(255), + + Forms\Components\TextInput::make('email') + ->email() + ->required() + ->maxLength(255), + + //Forms\Components\DateTimePicker::make('email_verified_at'), + + Forms\Components\TextInput::make('password') + ->password() + ->required() + ->maxLength(255), + + Forms\Components\Select::make('roles') + ->label('Roles') + ->relationship('roles', 'name') // Relación con el modelo Role + ->multiple() // Permite seleccionar varios roles + ->preload() // Carga la lista al abrir el formulario + ->searchable() // Permite buscar roles en la lista + ->required(), + ]); + } + + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('name') + ->searchable(), + Tables\Columns\TextColumn::make('email') + ->searchable(), + Tables\Columns\TextColumn::make('roles.name') // Muestra los roles + ->label('Roles') + ->badge() // Muestra los roles con etiquetas visuales + ->sortable() + ->searchable(), + Tables\Columns\TextColumn::make('created_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->filters([ + // + ]) + ->actions([ + Tables\Actions\EditAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + RelationManagers\RolesRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListUsers::route('/'), + 'create' => Pages\CreateUser::route('/create'), + 'edit' => Pages\EditUser::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/UserResource/Pages/CreateUser.php b/app/Filament/Resources/UserResource/Pages/CreateUser.php new file mode 100644 index 0000000..1fc157a --- /dev/null +++ b/app/Filament/Resources/UserResource/Pages/CreateUser.php @@ -0,0 +1,38 @@ + $data['name'], + 'email' => $data['email'], + 'password' => $data['password'], + ]); + + // Asignar roles si es necesario + if (isset($data['roles'])) { + $user->roles()->sync($data['roles']); + } + $password=$data['password']; + + // Enviar el correo de bienvenida + Mail::to($user->email)->send(new WelcomeUserMail($user, $password)); + + return $user; + } +} diff --git a/app/Filament/Resources/UserResource/Pages/EditUser.php b/app/Filament/Resources/UserResource/Pages/EditUser.php new file mode 100644 index 0000000..b8770a9 --- /dev/null +++ b/app/Filament/Resources/UserResource/Pages/EditUser.php @@ -0,0 +1,19 @@ +schema([ + Forms\Components\Select::make('roles') + ->relationship('roles', 'name') + ->multiple() + ->preload() + ->searchable(), + ]); + } + + public function table(Table $table): Table + { + return $table->columns([ + Tables\Columns\TextColumn::make('name')->sortable()->searchable(), + ]) + ->filters([]) + ->headerActions([ + Tables\Actions\AttachAction::make(), + ]) + ->actions([ + Tables\Actions\DetachAction::make(), + ]); + } +} diff --git a/app/Filament/Resources/VentaResource.php b/app/Filament/Resources/VentaResource.php new file mode 100644 index 0000000..10e498f --- /dev/null +++ b/app/Filament/Resources/VentaResource.php @@ -0,0 +1,142 @@ +user()->can('ver ventas'); + } + + public static function form(Form $form): Form + { + return $form + ->schema([ + Forms\Components\Select::make('cliente_id') + ->relationship('cliente', 'id'), + Forms\Components\TextInput::make('total') + ->required() + ->numeric(), + Forms\Components\TextInput::make('tipo_pago') + ->required(), + Forms\Components\TextInput::make('estado') + ->required(), + ]); + } + + + + public static function table(Table $table): Table + { + return $table + ->columns([ + Tables\Columns\TextColumn::make('cliente.numero_documento') + ->label('Cliente') + ->numeric() + ->sortable(), + Tables\Columns\TextColumn::make('total') + ->money('COP') + ->sortable(), + Tables\Columns\TextColumn::make('tipo_pago') + ->badge() + ->color(fn (string $state): string => match ($state) { + 'Efectivo' => 'success', + 'Transferencia' => 'info', + default => 'gray', + }), + Tables\Columns\TextColumn::make('estado') + ->badge() + ->color(fn (string $state): string => match ($state) { + 'Pagado' => 'success', + 'Pendiente' => 'warning', + 'Cancelado' => 'danger', + default => 'gray', + }), + Tables\Columns\TextColumn::make('bodegas_usadas') + ->label('Bodegas') + ->getStateUsing(function ($record) { + $bodegas = $record->detalles() + ->whereNotNull('bodega_id') + ->with('bodega') + ->get() + ->pluck('bodega.nombre') + ->unique() + ->filter() + ->values(); + + if ($bodegas->isEmpty()) { + return 'Stock directo'; + } + + return $bodegas->join(', '); + }) + ->badge() + ->color('info') + ->tooltip('Bodegas de donde se descontó el stock'), + Tables\Columns\TextColumn::make('created_at') + ->label('Fecha') + ->dateTime('d/m/Y H:i') + ->sortable(), + Tables\Columns\TextColumn::make('updated_at') + ->dateTime() + ->sortable() + ->toggleable(isToggledHiddenByDefault: true), + ]) + ->paginated(true) + //->paginationPageOptions([50]) + ->defaultSort('created_at', 'desc') + ->actions([ + Tables\Actions\EditAction::make(), + Action::make('recibo') + ->label('Recibo') + ->icon('heroicon-o-printer') + ->color('secondary') + ->url(fn($record) => route('imprimir-recibo', ['venta' => $record->id])) + ->openUrlInNewTab() + ]) + + + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } + + + public static function getRelations(): array + { + return [ + DetallesRelationManagerRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListVentas::route('/'), + 'create' => Pages\CreateVenta::route('/create'), + 'edit' => Pages\EditVenta::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Resources/VentaResource/Pages/CreateVenta.php b/app/Filament/Resources/VentaResource/Pages/CreateVenta.php new file mode 100644 index 0000000..e516afa --- /dev/null +++ b/app/Filament/Resources/VentaResource/Pages/CreateVenta.php @@ -0,0 +1,12 @@ +schema([ + Forms\Components\TextInput::make('detalles') + ->required() + ->maxLength(255), + ]); + } + + public function table(Table $table): Table + { + return $table + ->recordTitleAttribute('detalles') + ->columns([ + Tables\Columns\TextColumn::make('producto.nombre')->label('Producto'), + Tables\Columns\TextColumn::make('variante') + ->label('Variante') + ->formatStateUsing(function ($record) { + if ($record->variante) { + return $record->variante->color->name . ' / ' . $record->variante->size->name; + } + return '—'; + }), + Tables\Columns\TextColumn::make('cantidad')->label('Cantidad'), + Tables\Columns\TextColumn::make('precio_unitario')->label('Precio Unitario'), + Tables\Columns\TextColumn::make('subtotal')->label('Subtotal'), + ]) + ->filters([ + // + ]) + ->headerActions([ + /* Tables\Actions\CreateAction::make(), */ + ]) + ->actions([ + Tables\Actions\EditAction::make(), + Tables\Actions\DeleteAction::make(), + ]) + ->bulkActions([ + Tables\Actions\BulkActionGroup::make([ + Tables\Actions\DeleteBulkAction::make(), + ]), + ]); + } +} diff --git a/app/Filament/Widgets/AlertasStockBodegasWidget.php b/app/Filament/Widgets/AlertasStockBodegasWidget.php new file mode 100644 index 0000000..cb96e51 --- /dev/null +++ b/app/Filament/Widgets/AlertasStockBodegasWidget.php @@ -0,0 +1,76 @@ +get() + ->filter(function ($producto) { + return $producto->getStockEfectivo() <= $producto->stock_minimo; + }) + ->count(); + + $stats[] = Stat::make('Stock Bajo Global', $productosStockBajo) + ->description('Productos bajo mínimo') + ->descriptionIcon('heroicon-m-exclamation-triangle') + ->color($productosStockBajo > 0 ? 'danger' : 'success'); + + // Productos con stock alto general + $productosStockAlto = Producto::where('estado', true) + ->whereNotNull('stock_maximo') + ->get() + ->filter(function ($producto) { + return $producto->getStockEfectivo() > $producto->stock_maximo; + }) + ->count(); + + $stats[] = Stat::make('Stock Excesivo', $productosStockAlto) + ->description('Productos sobre máximo') + ->descriptionIcon('heroicon-m-arrow-trending-up') + ->color($productosStockAlto > 0 ? 'warning' : 'success'); + + // Análisis por bodega crítica (si existe) + $bodegaPrincipal = Bodega::where('nombre', 'Principal')->first(); + if ($bodegaPrincipal) { + $productosConStockCero = $bodegaPrincipal->productos() + ->wherePivot('stock', 0) + ->count(); + + $stats[] = Stat::make('Sin Stock en Principal', $productosConStockCero) + ->description('Productos agotados') + ->descriptionIcon('heroicon-m-x-circle') + ->color($productosConStockCero > 0 ? 'danger' : 'success'); + } + + return $stats; + + } catch (\Exception $e) { + // En caso de error, devolver estadísticas básicas + return [ + Stat::make('Sistema de Alertas', 'Configurando...') + ->description('Ejecute las migraciones necesarias') + ->descriptionIcon('heroicon-m-cog-6-tooth') + ->color('warning') + ]; + } + } + + protected function getColumns(): int + { + return 3; + } +} \ No newline at end of file diff --git a/app/Filament/Widgets/TransferenciasBodegaStatsWidget.php b/app/Filament/Widgets/TransferenciasBodegaStatsWidget.php new file mode 100644 index 0000000..4d0cf56 --- /dev/null +++ b/app/Filament/Widgets/TransferenciasBodegaStatsWidget.php @@ -0,0 +1,39 @@ +startOfWeek(); + $esteMes = Carbon::now()->startOfMonth(); + + $transferenciasHoy = TransferenciaBodega::whereDate('fecha_transferencia', $hoy)->count(); + $transferenciasEstaSemana = TransferenciaBodega::where('fecha_transferencia', '>=', $estaSemana)->count(); + $transferenciasEsteMes = TransferenciaBodega::where('fecha_transferencia', '>=', $esteMes)->count(); + + return [ + Stat::make('Transferencias Hoy', $transferenciasHoy) + ->description('Transferencias realizadas hoy') + ->descriptionIcon('heroicon-m-arrow-trending-up') + ->color('success'), + + Stat::make('Esta Semana', $transferenciasEstaSemana) + ->description('Transferencias esta semana') + ->descriptionIcon('heroicon-m-calendar-days') + ->color('warning'), + + Stat::make('Este Mes', $transferenciasEsteMes) + ->description('Transferencias este mes') + ->descriptionIcon('heroicon-m-chart-bar') + ->color('primary'), + ]; + } +} \ No newline at end of file diff --git a/app/Filament/Widgets/VentasChart.php b/app/Filament/Widgets/VentasChart.php new file mode 100644 index 0000000..b90ea1d --- /dev/null +++ b/app/Filament/Widgets/VentasChart.php @@ -0,0 +1,36 @@ +startOfMonth(), Carbon::now()->endOfMonth()]) + ->groupByRaw('DATE(created_at)') + ->selectRaw('DATE(created_at) as dia, SUM(total) as total') + ->pluck('total', 'dia'); + + + return [ + 'datasets' => [ + [ + 'label' => 'Ventas del mes', + 'data' => array_values($ventas->toArray()), + ], + ], + 'labels' => array_keys($ventas->toArray()), + ]; + } + + protected function getType(): string + { + return 'bar'; + } +} diff --git a/app/Hashing/PBKDF2Hasher.php b/app/Hashing/PBKDF2Hasher.php new file mode 100644 index 0000000..7473763 --- /dev/null +++ b/app/Hashing/PBKDF2Hasher.php @@ -0,0 +1,66 @@ +iterations = 870000; // Debe coincidir con las iteraciones en Django + $this->saltLength = 22; // Puedes ajustar el tamaño del salt según lo que prefieras + $this->algorithm = 'sha256'; // Algoritmo utilizado (puede ser sha256, sha512, etc.) + } + + public function make($value, array $options = []) + { + + $salt = Str::random($this->saltLength); // Genera un salt aleatorio de 22 caracteres + $hash = hash_pbkdf2($this->algorithm, $value, $salt, $this->iterations, 64, false); + return "pbkdf2_sha256$$this->iterations$$salt$$hash"; + } + + public function check($value, $hashedValue, array $options = []) + { + $parts = explode('$', $hashedValue); + if (count($parts) !== 4) { + return false; + } + + list(, $iterations, $salt, $hash) = $parts; + + // Verificar si la contraseña coincide + $newHash = hash_pbkdf2($this->algorithm, $value, $salt, $iterations, 64, false); + + return hash_equals($newHash, $hash); // Comparar hashes de manera segura + } + + public function info($hashedValue) + { + $parts = explode('$', $hashedValue); + if (count($parts) !== 4) { + return []; + } + + list(, $iterations, $salt, $hash) = $parts; + + return [ + 'algorithm' => $this->algorithm, + 'iterations' => (int) $iterations, + 'salt' => $salt, + 'hash' => $hash, + ]; + } + + public function needsRehash($hashedValue, array $options = []) + { + // Si necesitas implementar una lógica para verificar si el hash necesita rehacerse + return false; + } +} diff --git a/app/Http/Controllers/CajaController.php b/app/Http/Controllers/CajaController.php new file mode 100644 index 0000000..b5d19bc --- /dev/null +++ b/app/Http/Controllers/CajaController.php @@ -0,0 +1,47 @@ +validated()); + + return new CajaResource($caja); + } + + public function show(Request $request, Caja $caja): CajaResource + { + return new CajaResource($caja); + } + + public function update(CajaUpdateRequest $request, Caja $caja): CajaResource + { + $caja->update($request->validated()); + + return new CajaResource($caja); + } + + public function destroy(Request $request, Caja $caja): Response + { + $caja->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/CategoriaController.php b/app/Http/Controllers/CategoriaController.php new file mode 100644 index 0000000..e5b5426 --- /dev/null +++ b/app/Http/Controllers/CategoriaController.php @@ -0,0 +1,47 @@ +validated()); + + return new CategoriumResource($categorium); + } + + public function show(Request $request, Categorium $categorium): CategoriumResource + { + return new CategoriumResource($categorium); + } + + public function update(CategoriumUpdateRequest $request, Categorium $categorium): CategoriumResource + { + $categorium->update($request->validated()); + + return new CategoriumResource($categorium); + } + + public function destroy(Request $request, Categorium $categorium): Response + { + $categorium->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/ClienteController.php b/app/Http/Controllers/ClienteController.php new file mode 100644 index 0000000..9ac390c --- /dev/null +++ b/app/Http/Controllers/ClienteController.php @@ -0,0 +1,47 @@ +validated()); + + return new ClienteResource($cliente); + } + + public function show(Request $request, Cliente $cliente): ClienteResource + { + return new ClienteResource($cliente); + } + + public function update(ClienteUpdateRequest $request, Cliente $cliente): ClienteResource + { + $cliente->update($request->validated()); + + return new ClienteResource($cliente); + } + + public function destroy(Request $request, Cliente $cliente): Response + { + $cliente->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/CompraController.php b/app/Http/Controllers/CompraController.php new file mode 100644 index 0000000..fb07356 --- /dev/null +++ b/app/Http/Controllers/CompraController.php @@ -0,0 +1,47 @@ +validated()); + + return new CompraResource($compra); + } + + public function show(Request $request, Compra $compra): CompraResource + { + return new CompraResource($compra); + } + + public function update(CompraUpdateRequest $request, Compra $compra): CompraResource + { + $compra->update($request->validated()); + + return new CompraResource($compra); + } + + public function destroy(Request $request, Compra $compra): Response + { + $compra->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..8677cd5 --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,8 @@ +validated()); + + return new DetalleCompraResource($detalleCompra); + } + + public function show(Request $request, DetalleCompra $detalleCompra): DetalleCompraResource + { + return new DetalleCompraResource($detalleCompra); + } + + public function update(DetalleCompraUpdateRequest $request, DetalleCompra $detalleCompra): DetalleCompraResource + { + $detalleCompra->update($request->validated()); + + return new DetalleCompraResource($detalleCompra); + } + + public function destroy(Request $request, DetalleCompra $detalleCompra): Response + { + $detalleCompra->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/DetalleVentaController.php b/app/Http/Controllers/DetalleVentaController.php new file mode 100644 index 0000000..9df8be6 --- /dev/null +++ b/app/Http/Controllers/DetalleVentaController.php @@ -0,0 +1,47 @@ +validated()); + + return new DetalleVentumResource($detalleVentum); + } + + public function show(Request $request, DetalleVentum $detalleVentum): DetalleVentumResource + { + return new DetalleVentumResource($detalleVentum); + } + + public function update(DetalleVentumUpdateRequest $request, DetalleVentum $detalleVentum): DetalleVentumResource + { + $detalleVentum->update($request->validated()); + + return new DetalleVentumResource($detalleVentum); + } + + public function destroy(Request $request, DetalleVentum $detalleVentum): Response + { + $detalleVentum->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/InventarioController.php b/app/Http/Controllers/InventarioController.php new file mode 100644 index 0000000..097cad4 --- /dev/null +++ b/app/Http/Controllers/InventarioController.php @@ -0,0 +1,47 @@ +validated()); + + return new InventarioResource($inventario); + } + + public function show(Request $request, Inventario $inventario): InventarioResource + { + return new InventarioResource($inventario); + } + + public function update(InventarioUpdateRequest $request, Inventario $inventario): InventarioResource + { + $inventario->update($request->validated()); + + return new InventarioResource($inventario); + } + + public function destroy(Request $request, Inventario $inventario): Response + { + $inventario->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/MovimientoCajaController.php b/app/Http/Controllers/MovimientoCajaController.php new file mode 100644 index 0000000..f8e3a27 --- /dev/null +++ b/app/Http/Controllers/MovimientoCajaController.php @@ -0,0 +1,47 @@ +validated()); + + return new MovimientoCajaResource($movimientoCaja); + } + + public function show(Request $request, MovimientoCaja $movimientoCaja): MovimientoCajaResource + { + return new MovimientoCajaResource($movimientoCaja); + } + + public function update(MovimientoCajaUpdateRequest $request, MovimientoCaja $movimientoCaja): MovimientoCajaResource + { + $movimientoCaja->update($request->validated()); + + return new MovimientoCajaResource($movimientoCaja); + } + + public function destroy(Request $request, MovimientoCaja $movimientoCaja): Response + { + $movimientoCaja->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/ProductoController.php b/app/Http/Controllers/ProductoController.php new file mode 100644 index 0000000..572f25b --- /dev/null +++ b/app/Http/Controllers/ProductoController.php @@ -0,0 +1,47 @@ +validated()); + + return new ProductoResource($producto); + } + + public function show(Request $request, Producto $producto): ProductoResource + { + return new ProductoResource($producto); + } + + public function update(ProductoUpdateRequest $request, Producto $producto): ProductoResource + { + $producto->update($request->validated()); + + return new ProductoResource($producto); + } + + public function destroy(Request $request, Producto $producto): Response + { + $producto->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/ProveedorController.php b/app/Http/Controllers/ProveedorController.php new file mode 100644 index 0000000..ab36440 --- /dev/null +++ b/app/Http/Controllers/ProveedorController.php @@ -0,0 +1,47 @@ +validated()); + + return new ProveedorResource($proveedor); + } + + public function show(Request $request, Proveedor $proveedor): ProveedorResource + { + return new ProveedorResource($proveedor); + } + + public function update(ProveedorUpdateRequest $request, Proveedor $proveedor): ProveedorResource + { + $proveedor->update($request->validated()); + + return new ProveedorResource($proveedor); + } + + public function destroy(Request $request, Proveedor $proveedor): Response + { + $proveedor->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/SettingController.php b/app/Http/Controllers/SettingController.php new file mode 100644 index 0000000..e9c98cf --- /dev/null +++ b/app/Http/Controllers/SettingController.php @@ -0,0 +1,47 @@ +validated()); + + return new SettingResource($setting); + } + + public function show(Request $request, Setting $setting): SettingResource + { + return new SettingResource($setting); + } + + public function update(SettingUpdateRequest $request, Setting $setting): SettingResource + { + $setting->update($request->validated()); + + return new SettingResource($setting); + } + + public function destroy(Request $request, Setting $setting): Response + { + $setting->delete(); + + return response()->noContent(); + } +} diff --git a/app/Http/Controllers/VentaController.php b/app/Http/Controllers/VentaController.php new file mode 100644 index 0000000..eb3dbeb --- /dev/null +++ b/app/Http/Controllers/VentaController.php @@ -0,0 +1,52 @@ +validated()); + + return new VentumResource($ventum); + } + + public function show(Request $request, Ventum $ventum): VentumResource + { + return new VentumResource($ventum); + } + + public function update(VentumUpdateRequest $request, Ventum $ventum): VentumResource + { + $ventum->update($request->validated()); + + return new VentumResource($ventum); + } + + public function destroy(Request $request, Ventum $ventum): Response + { + $ventum->delete(); + + return response()->noContent(); + } + + public function imprimirRecibo(Venta $venta) + { + return view('recibos.ticket', compact('venta')); + } +} diff --git a/app/Http/Requests/CajaStoreRequest.php b/app/Http/Requests/CajaStoreRequest.php new file mode 100644 index 0000000..27afb12 --- /dev/null +++ b/app/Http/Requests/CajaStoreRequest.php @@ -0,0 +1,30 @@ + ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'monto_final' => ['nullable', 'numeric', 'between:-99999999.99,99999999.99'], + 'fecha_apertura' => ['required'], + 'fecha_cierre' => ['nullable'], + 'estado' => ['required', 'in:Abierta,Cerrada'], + ]; + } +} diff --git a/app/Http/Requests/CajaUpdateRequest.php b/app/Http/Requests/CajaUpdateRequest.php new file mode 100644 index 0000000..8284d2b --- /dev/null +++ b/app/Http/Requests/CajaUpdateRequest.php @@ -0,0 +1,30 @@ + ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'monto_final' => ['nullable', 'numeric', 'between:-99999999.99,99999999.99'], + 'fecha_apertura' => ['required'], + 'fecha_cierre' => ['nullable'], + 'estado' => ['required', 'in:Abierta,Cerrada'], + ]; + } +} diff --git a/app/Http/Requests/CategoriumStoreRequest.php b/app/Http/Requests/CategoriumStoreRequest.php new file mode 100644 index 0000000..2d5ca48 --- /dev/null +++ b/app/Http/Requests/CategoriumStoreRequest.php @@ -0,0 +1,27 @@ + ['required', 'string', 'max:255'], + 'descripcion' => ['nullable', 'string'], + ]; + } +} diff --git a/app/Http/Requests/CategoriumUpdateRequest.php b/app/Http/Requests/CategoriumUpdateRequest.php new file mode 100644 index 0000000..8ed3383 --- /dev/null +++ b/app/Http/Requests/CategoriumUpdateRequest.php @@ -0,0 +1,27 @@ + ['required', 'string', 'max:255'], + 'descripcion' => ['nullable', 'string'], + ]; + } +} diff --git a/app/Http/Requests/ClienteStoreRequest.php b/app/Http/Requests/ClienteStoreRequest.php new file mode 100644 index 0000000..a4c9918 --- /dev/null +++ b/app/Http/Requests/ClienteStoreRequest.php @@ -0,0 +1,31 @@ + ['required', 'string', 'max:255'], + 'correo' => ['nullable', 'string', 'max:255', 'unique:clientes,correo'], + 'telefono' => ['nullable', 'string', 'max:20'], + 'direccion' => ['nullable', 'string'], + 'tipo_documento' => ['required', 'in:DNI,RUC,PASAPORTE'], + 'numero_documento' => ['required', 'string', 'max:20', 'unique:clientes,numero_documento'], + ]; + } +} diff --git a/app/Http/Requests/ClienteUpdateRequest.php b/app/Http/Requests/ClienteUpdateRequest.php new file mode 100644 index 0000000..7a2fb01 --- /dev/null +++ b/app/Http/Requests/ClienteUpdateRequest.php @@ -0,0 +1,31 @@ + ['required', 'string', 'max:255'], + 'correo' => ['nullable', 'string', 'max:255', 'unique:clientes,correo'], + 'telefono' => ['nullable', 'string', 'max:20'], + 'direccion' => ['nullable', 'string'], + 'tipo_documento' => ['required', 'in:DNI,RUC,PASAPORTE'], + 'numero_documento' => ['required', 'string', 'max:20', 'unique:clientes,numero_documento'], + ]; + } +} diff --git a/app/Http/Requests/CompraStoreRequest.php b/app/Http/Requests/CompraStoreRequest.php new file mode 100644 index 0000000..c01e1ac --- /dev/null +++ b/app/Http/Requests/CompraStoreRequest.php @@ -0,0 +1,29 @@ + ['required'], + 'proveedor_id' => ['nullable', 'integer', 'exists:proveedores,id'], + 'total' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'estado' => ['required', 'in:Recibida,Pendiente,Anulada'], + ]; + } +} diff --git a/app/Http/Requests/CompraUpdateRequest.php b/app/Http/Requests/CompraUpdateRequest.php new file mode 100644 index 0000000..dc964f4 --- /dev/null +++ b/app/Http/Requests/CompraUpdateRequest.php @@ -0,0 +1,29 @@ + ['required'], + 'proveedor_id' => ['nullable', 'integer', 'exists:proveedores,id'], + 'total' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'estado' => ['required', 'in:Recibida,Pendiente,Anulada'], + ]; + } +} diff --git a/app/Http/Requests/DetalleCompraStoreRequest.php b/app/Http/Requests/DetalleCompraStoreRequest.php new file mode 100644 index 0000000..d6a6e3d --- /dev/null +++ b/app/Http/Requests/DetalleCompraStoreRequest.php @@ -0,0 +1,30 @@ + ['required', 'integer', 'exists:compras,id'], + 'producto_id' => ['required', 'integer', 'exists:productos,id'], + 'cantidad' => ['required', 'integer'], + 'precio_unitario' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'subtotal' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + ]; + } +} diff --git a/app/Http/Requests/DetalleCompraUpdateRequest.php b/app/Http/Requests/DetalleCompraUpdateRequest.php new file mode 100644 index 0000000..5fad327 --- /dev/null +++ b/app/Http/Requests/DetalleCompraUpdateRequest.php @@ -0,0 +1,30 @@ + ['required', 'integer', 'exists:compras,id'], + 'producto_id' => ['required', 'integer', 'exists:productos,id'], + 'cantidad' => ['required', 'integer'], + 'precio_unitario' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'subtotal' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + ]; + } +} diff --git a/app/Http/Requests/DetalleVentumStoreRequest.php b/app/Http/Requests/DetalleVentumStoreRequest.php new file mode 100644 index 0000000..64253e6 --- /dev/null +++ b/app/Http/Requests/DetalleVentumStoreRequest.php @@ -0,0 +1,30 @@ + ['required', 'integer', 'exists:ventas,id'], + 'producto_id' => ['required', 'integer', 'exists:productos,id'], + 'cantidad' => ['required', 'integer'], + 'precio_unitario' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'subtotal' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + ]; + } +} diff --git a/app/Http/Requests/DetalleVentumUpdateRequest.php b/app/Http/Requests/DetalleVentumUpdateRequest.php new file mode 100644 index 0000000..03ea7a4 --- /dev/null +++ b/app/Http/Requests/DetalleVentumUpdateRequest.php @@ -0,0 +1,30 @@ + ['required', 'integer', 'exists:ventas,id'], + 'producto_id' => ['required', 'integer', 'exists:productos,id'], + 'cantidad' => ['required', 'integer'], + 'precio_unitario' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'subtotal' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + ]; + } +} diff --git a/app/Http/Requests/InventarioStoreRequest.php b/app/Http/Requests/InventarioStoreRequest.php new file mode 100644 index 0000000..5548cd2 --- /dev/null +++ b/app/Http/Requests/InventarioStoreRequest.php @@ -0,0 +1,29 @@ + ['required', 'integer', 'exists:productos,id'], + 'stock_actual' => ['required', 'integer'], + 'stock_minimo' => ['required', 'integer'], + 'ubicacion' => ['nullable', 'string', 'max:255'], + ]; + } +} diff --git a/app/Http/Requests/InventarioUpdateRequest.php b/app/Http/Requests/InventarioUpdateRequest.php new file mode 100644 index 0000000..aa8bbd2 --- /dev/null +++ b/app/Http/Requests/InventarioUpdateRequest.php @@ -0,0 +1,29 @@ + ['required', 'integer', 'exists:productos,id'], + 'stock_actual' => ['required', 'integer'], + 'stock_minimo' => ['required', 'integer'], + 'ubicacion' => ['nullable', 'string', 'max:255'], + ]; + } +} diff --git a/app/Http/Requests/MovimientoCajaStoreRequest.php b/app/Http/Requests/MovimientoCajaStoreRequest.php new file mode 100644 index 0000000..f633a0e --- /dev/null +++ b/app/Http/Requests/MovimientoCajaStoreRequest.php @@ -0,0 +1,30 @@ + ['required', 'integer', 'exists:cajas,id'], + 'tipo' => ['required', 'in:Ingreso,Egreso'], + 'monto' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'descripcion' => ['nullable', 'string'], + 'fecha' => ['required'], + ]; + } +} diff --git a/app/Http/Requests/MovimientoCajaUpdateRequest.php b/app/Http/Requests/MovimientoCajaUpdateRequest.php new file mode 100644 index 0000000..f286906 --- /dev/null +++ b/app/Http/Requests/MovimientoCajaUpdateRequest.php @@ -0,0 +1,30 @@ + ['required', 'integer', 'exists:cajas,id'], + 'tipo' => ['required', 'in:Ingreso,Egreso'], + 'monto' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'descripcion' => ['nullable', 'string'], + 'fecha' => ['required'], + ]; + } +} diff --git a/app/Http/Requests/ProductoStoreRequest.php b/app/Http/Requests/ProductoStoreRequest.php new file mode 100644 index 0000000..9a8be68 --- /dev/null +++ b/app/Http/Requests/ProductoStoreRequest.php @@ -0,0 +1,33 @@ + ['required', 'string', 'max:255'], + 'descripcion' => ['nullable', 'string'], + 'codigo_barras' => ['required', 'string', 'max:50', 'unique:productos,codigo_barras'], + 'precio_compra' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'precio_venta' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'stock' => ['required', 'integer'], + 'categoria_id' => ['required', 'integer', 'exists:categorias,id'], + 'estado' => ['required', 'in:activo,inactivo'], + ]; + } +} diff --git a/app/Http/Requests/ProductoUpdateRequest.php b/app/Http/Requests/ProductoUpdateRequest.php new file mode 100644 index 0000000..77f73ee --- /dev/null +++ b/app/Http/Requests/ProductoUpdateRequest.php @@ -0,0 +1,33 @@ + ['required', 'string', 'max:255'], + 'descripcion' => ['nullable', 'string'], + 'codigo_barras' => ['required', 'string', 'max:50', 'unique:productos,codigo_barras'], + 'precio_compra' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'precio_venta' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'stock' => ['required', 'integer'], + 'categoria_id' => ['required', 'integer', 'exists:categorias,id'], + 'estado' => ['required', 'in:activo,inactivo'], + ]; + } +} diff --git a/app/Http/Requests/ProveedorStoreRequest.php b/app/Http/Requests/ProveedorStoreRequest.php new file mode 100644 index 0000000..5bbe1e7 --- /dev/null +++ b/app/Http/Requests/ProveedorStoreRequest.php @@ -0,0 +1,30 @@ + ['required', 'string', 'max:255'], + 'contacto' => ['nullable', 'string', 'max:255'], + 'telefono' => ['nullable', 'string', 'max:20'], + 'correo' => ['nullable', 'string', 'max:255', 'unique:proveedors,correo'], + 'direccion' => ['nullable', 'string'], + ]; + } +} diff --git a/app/Http/Requests/ProveedorUpdateRequest.php b/app/Http/Requests/ProveedorUpdateRequest.php new file mode 100644 index 0000000..da2579e --- /dev/null +++ b/app/Http/Requests/ProveedorUpdateRequest.php @@ -0,0 +1,30 @@ + ['required', 'string', 'max:255'], + 'contacto' => ['nullable', 'string', 'max:255'], + 'telefono' => ['nullable', 'string', 'max:20'], + 'correo' => ['nullable', 'string', 'max:255', 'unique:proveedors,correo'], + 'direccion' => ['nullable', 'string'], + ]; + } +} diff --git a/app/Http/Requests/SettingStoreRequest.php b/app/Http/Requests/SettingStoreRequest.php new file mode 100644 index 0000000..b08f91a --- /dev/null +++ b/app/Http/Requests/SettingStoreRequest.php @@ -0,0 +1,31 @@ + ['nullable', 'string'], + 'description' => ['nullable', 'string'], + 'primary_color' => ['nullable', 'string'], + 'secondary_color' => ['nullable', 'string'], + 'created_at' => ['nullable'], + 'updated_at' => ['nullable'], + ]; + } +} diff --git a/app/Http/Requests/SettingUpdateRequest.php b/app/Http/Requests/SettingUpdateRequest.php new file mode 100644 index 0000000..1064745 --- /dev/null +++ b/app/Http/Requests/SettingUpdateRequest.php @@ -0,0 +1,31 @@ + ['nullable', 'string'], + 'description' => ['nullable', 'string'], + 'primary_color' => ['nullable', 'string'], + 'secondary_color' => ['nullable', 'string'], + 'created_at' => ['nullable'], + 'updated_at' => ['nullable'], + ]; + } +} diff --git a/app/Http/Requests/VentumStoreRequest.php b/app/Http/Requests/VentumStoreRequest.php new file mode 100644 index 0000000..0948ed0 --- /dev/null +++ b/app/Http/Requests/VentumStoreRequest.php @@ -0,0 +1,30 @@ + ['required'], + 'cliente_id' => ['nullable', 'integer', 'exists:clientes,id'], + 'total' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'tipo_pago' => ['required', 'in:Efectivo,Tarjeta,Transferencia'], + 'estado' => ['required', 'in:Pagado,Pendiente,Anulado'], + ]; + } +} diff --git a/app/Http/Requests/VentumUpdateRequest.php b/app/Http/Requests/VentumUpdateRequest.php new file mode 100644 index 0000000..de7e980 --- /dev/null +++ b/app/Http/Requests/VentumUpdateRequest.php @@ -0,0 +1,30 @@ + ['required'], + 'cliente_id' => ['nullable', 'integer', 'exists:clientes,id'], + 'total' => ['required', 'numeric', 'between:-99999999.99,99999999.99'], + 'tipo_pago' => ['required', 'in:Efectivo,Tarjeta,Transferencia'], + 'estado' => ['required', 'in:Pagado,Pendiente,Anulado'], + ]; + } +} diff --git a/app/Http/Resources/CajaCollection.php b/app/Http/Resources/CajaCollection.php new file mode 100644 index 0000000..c0467cf --- /dev/null +++ b/app/Http/Resources/CajaCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/CajaResource.php b/app/Http/Resources/CajaResource.php new file mode 100644 index 0000000..0790ee0 --- /dev/null +++ b/app/Http/Resources/CajaResource.php @@ -0,0 +1,24 @@ + $this->id, + 'monto_inicial' => $this->monto_inicial, + 'monto_final' => $this->monto_final, + 'fecha_apertura' => $this->fecha_apertura, + 'fecha_cierre' => $this->fecha_cierre, + 'estado' => $this->estado, + ]; + } +} diff --git a/app/Http/Resources/CategoriumCollection.php b/app/Http/Resources/CategoriumCollection.php new file mode 100644 index 0000000..34f07e0 --- /dev/null +++ b/app/Http/Resources/CategoriumCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/CategoriumResource.php b/app/Http/Resources/CategoriumResource.php new file mode 100644 index 0000000..28f7d9e --- /dev/null +++ b/app/Http/Resources/CategoriumResource.php @@ -0,0 +1,21 @@ + $this->id, + 'nombre' => $this->nombre, + 'descripcion' => $this->descripcion, + ]; + } +} diff --git a/app/Http/Resources/ClienteCollection.php b/app/Http/Resources/ClienteCollection.php new file mode 100644 index 0000000..559fc85 --- /dev/null +++ b/app/Http/Resources/ClienteCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/ClienteResource.php b/app/Http/Resources/ClienteResource.php new file mode 100644 index 0000000..0da11b0 --- /dev/null +++ b/app/Http/Resources/ClienteResource.php @@ -0,0 +1,25 @@ + $this->id, + 'nombre' => $this->nombre, + 'correo' => $this->correo, + 'telefono' => $this->telefono, + 'direccion' => $this->direccion, + 'tipo_documento' => $this->tipo_documento, + 'numero_documento' => $this->numero_documento, + ]; + } +} diff --git a/app/Http/Resources/CompraCollection.php b/app/Http/Resources/CompraCollection.php new file mode 100644 index 0000000..4345ae5 --- /dev/null +++ b/app/Http/Resources/CompraCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/CompraResource.php b/app/Http/Resources/CompraResource.php new file mode 100644 index 0000000..431c820 --- /dev/null +++ b/app/Http/Resources/CompraResource.php @@ -0,0 +1,23 @@ + $this->id, + 'fecha' => $this->fecha, + 'proveedor_id' => $this->proveedor_id, + 'total' => $this->total, + 'estado' => $this->estado, + ]; + } +} diff --git a/app/Http/Resources/DetalleCompraCollection.php b/app/Http/Resources/DetalleCompraCollection.php new file mode 100644 index 0000000..bce09d5 --- /dev/null +++ b/app/Http/Resources/DetalleCompraCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/DetalleCompraResource.php b/app/Http/Resources/DetalleCompraResource.php new file mode 100644 index 0000000..35f6a9b --- /dev/null +++ b/app/Http/Resources/DetalleCompraResource.php @@ -0,0 +1,24 @@ + $this->id, + 'compra_id' => $this->compra_id, + 'producto_id' => $this->producto_id, + 'cantidad' => $this->cantidad, + 'precio_unitario' => $this->precio_unitario, + 'subtotal' => $this->subtotal, + ]; + } +} diff --git a/app/Http/Resources/DetalleVentumCollection.php b/app/Http/Resources/DetalleVentumCollection.php new file mode 100644 index 0000000..a3f94e9 --- /dev/null +++ b/app/Http/Resources/DetalleVentumCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/DetalleVentumResource.php b/app/Http/Resources/DetalleVentumResource.php new file mode 100644 index 0000000..b0f8950 --- /dev/null +++ b/app/Http/Resources/DetalleVentumResource.php @@ -0,0 +1,24 @@ + $this->id, + 'venta_id' => $this->venta_id, + 'producto_id' => $this->producto_id, + 'cantidad' => $this->cantidad, + 'precio_unitario' => $this->precio_unitario, + 'subtotal' => $this->subtotal, + ]; + } +} diff --git a/app/Http/Resources/InventarioCollection.php b/app/Http/Resources/InventarioCollection.php new file mode 100644 index 0000000..29da94f --- /dev/null +++ b/app/Http/Resources/InventarioCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/InventarioResource.php b/app/Http/Resources/InventarioResource.php new file mode 100644 index 0000000..0f69abe --- /dev/null +++ b/app/Http/Resources/InventarioResource.php @@ -0,0 +1,23 @@ + $this->id, + 'producto_id' => $this->producto_id, + 'stock_actual' => $this->stock_actual, + 'stock_minimo' => $this->stock_minimo, + 'ubicacion' => $this->ubicacion, + ]; + } +} diff --git a/app/Http/Resources/MovimientoCajaCollection.php b/app/Http/Resources/MovimientoCajaCollection.php new file mode 100644 index 0000000..2812243 --- /dev/null +++ b/app/Http/Resources/MovimientoCajaCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/MovimientoCajaResource.php b/app/Http/Resources/MovimientoCajaResource.php new file mode 100644 index 0000000..748ef28 --- /dev/null +++ b/app/Http/Resources/MovimientoCajaResource.php @@ -0,0 +1,24 @@ + $this->id, + 'caja_id' => $this->caja_id, + 'tipo' => $this->tipo, + 'monto' => $this->monto, + 'descripcion' => $this->descripcion, + 'fecha' => $this->fecha, + ]; + } +} diff --git a/app/Http/Resources/ProductoCollection.php b/app/Http/Resources/ProductoCollection.php new file mode 100644 index 0000000..9f5c0cc --- /dev/null +++ b/app/Http/Resources/ProductoCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/ProductoResource.php b/app/Http/Resources/ProductoResource.php new file mode 100644 index 0000000..8a9f18e --- /dev/null +++ b/app/Http/Resources/ProductoResource.php @@ -0,0 +1,27 @@ + $this->id, + 'nombre' => $this->nombre, + 'descripcion' => $this->descripcion, + 'codigo_barras' => $this->codigo_barras, + 'precio_compra' => $this->precio_compra, + 'precio_venta' => $this->precio_venta, + 'stock' => $this->stock, + 'categoria_id' => $this->categoria_id, + 'estado' => $this->estado, + ]; + } +} diff --git a/app/Http/Resources/ProveedorCollection.php b/app/Http/Resources/ProveedorCollection.php new file mode 100644 index 0000000..58c4e89 --- /dev/null +++ b/app/Http/Resources/ProveedorCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/ProveedorResource.php b/app/Http/Resources/ProveedorResource.php new file mode 100644 index 0000000..7644572 --- /dev/null +++ b/app/Http/Resources/ProveedorResource.php @@ -0,0 +1,24 @@ + $this->id, + 'nombre' => $this->nombre, + 'contacto' => $this->contacto, + 'telefono' => $this->telefono, + 'correo' => $this->correo, + 'direccion' => $this->direccion, + ]; + } +} diff --git a/app/Http/Resources/SettingCollection.php b/app/Http/Resources/SettingCollection.php new file mode 100644 index 0000000..91bf1ea --- /dev/null +++ b/app/Http/Resources/SettingCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/SettingResource.php b/app/Http/Resources/SettingResource.php new file mode 100644 index 0000000..4734e1b --- /dev/null +++ b/app/Http/Resources/SettingResource.php @@ -0,0 +1,25 @@ + $this->id, + 'logo' => $this->logo, + 'description' => $this->description, + 'primary_color' => $this->primary_color, + 'secondary_color' => $this->secondary_color, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} diff --git a/app/Http/Resources/VentumCollection.php b/app/Http/Resources/VentumCollection.php new file mode 100644 index 0000000..6a1f347 --- /dev/null +++ b/app/Http/Resources/VentumCollection.php @@ -0,0 +1,19 @@ + $this->collection, + ]; + } +} diff --git a/app/Http/Resources/VentumResource.php b/app/Http/Resources/VentumResource.php new file mode 100644 index 0000000..4b54f62 --- /dev/null +++ b/app/Http/Resources/VentumResource.php @@ -0,0 +1,24 @@ + $this->id, + 'fecha' => $this->fecha, + 'cliente_id' => $this->cliente_id, + 'total' => $this->total, + 'tipo_pago' => $this->tipo_pago, + 'estado' => $this->estado, + ]; + } +} diff --git a/app/Imports/CompraDetallesImport.php b/app/Imports/CompraDetallesImport.php new file mode 100644 index 0000000..82b206a --- /dev/null +++ b/app/Imports/CompraDetallesImport.php @@ -0,0 +1,295 @@ +previewData = []; + $rowNumber = 2; // Comenzar en 2 porque fila 1 son los encabezados + + foreach ($rows as $row) { + $detalle = $this->processRow($row->toArray(), $rowNumber); + $this->previewData[] = $detalle; + $rowNumber++; + } + } + + /** + * Procesa una fila individual + */ + private function processRow(array $row, int $rowNumber): array + { + $result = [ + 'row_number' => $rowNumber, + 'valid' => true, + 'errors' => [], + 'data' => [], + 'producto_creado' => false, + ]; + + // Normalizar nombres de columnas + $row = $this->normalizeKeys($row); + + // Buscar o crear producto + $producto = null; + $variante = null; + $productoCreado = false; + + // 1. Primero intentar buscar por código de barras + if (!empty($row['codigo_barras'])) { + // Buscar variante primero + $variante = ProductVariant::where('barcode', $row['codigo_barras'])->first(); + if ($variante) { + $producto = $variante->producto; + } else { + // Buscar producto por código + $producto = Producto::where('codigo_barras', $row['codigo_barras'])->first(); + } + } + + // 2. Si no se encontró por código, buscar por nombre + if (!$producto && !empty($row['producto'])) { + $producto = Producto::where('nombre', 'like', '%' . trim($row['producto']) . '%')->first(); + } + + // 3. Si no existe, crear el producto + if (!$producto) { + // Validar que tenga al menos nombre o código + if (empty($row['producto']) && empty($row['codigo_barras'])) { + $result['valid'] = false; + $result['errors'][] = 'Debe proporcionar código de barras o nombre del producto'; + } else { + $nombreProducto = !empty($row['producto']) ? trim($row['producto']) : 'Producto ' . $row['codigo_barras']; + $precioUnitario = isset($row['precio_unitario']) ? (float) $row['precio_unitario'] : 0; + + if ($precioUnitario <= 0) { + $result['valid'] = false; + $result['errors'][] = 'Precio debe ser mayor a 0 para crear producto'; + } else { + // Buscar o crear categoría "Importados" + $categoria = \App\Models\Categoria::firstOrCreate( + ['nombre' => 'Importados'], + ['descripcion' => 'Productos creados automáticamente durante importación de compras'] + ); + + // Generar código de barras único si no se proporcionó + $codigoBarras = !empty($row['codigo_barras']) ? $row['codigo_barras'] : null; + + if (!$codigoBarras) { + // Generar código único: IMP + timestamp + random + do { + $codigoBarras = 'IMP' . time() . rand(100, 999); + } while (Producto::where('codigo_barras', $codigoBarras)->exists()); + } + + $producto = Producto::create([ + 'nombre' => $nombreProducto, + 'descripcion' => 'Creado automáticamente desde importación', + 'codigo_barras' => $codigoBarras, + 'categoria_id' => $categoria->id, + 'precio_compra' => $precioUnitario, + 'precio_venta' => round($precioUnitario * 1.3, 2), // 30% de margen por defecto + 'unidad_medida' => 'unidad', + 'estado' => true, + 'imagen' => '', + ]); + + $productoCreado = true; + $result['producto_creado'] = true; + } + } + } + + // Buscar bodega + $bodega = null; + if (!empty($row['bodega'])) { + $bodega = Bodega::where('nombre', 'like', '%' . $row['bodega'] . '%')->first(); + } else { + $bodega = Bodega::where('nombre', 'Principal')->first(); + } + + if (!$bodega) { + $result['valid'] = false; + $result['errors'][] = 'Bodega no encontrada'; + } + + // Validar cantidad + $cantidad = isset($row['cantidad']) ? (int) $row['cantidad'] : 1; + if ($cantidad <= 0) { + $result['valid'] = false; + $result['errors'][] = 'Cantidad debe ser mayor a 0'; + } + + // Validar precio + $precio = isset($row['precio_unitario']) ? (float) $row['precio_unitario'] : 0; + if ($precio <= 0) { + $result['valid'] = false; + $result['errors'][] = 'Precio debe ser mayor a 0'; + } + + // Calcular subtotal + $subtotal = $cantidad * $precio; + + // Preparar datos + $result['data'] = [ + 'codigo_barras' => $row['codigo_barras'] ?? '', + 'producto_nombre_excel' => $row['producto'] ?? '', + 'bodega_id' => $bodega?->id, + 'bodega_nombre' => $bodega?->nombre ?? 'No encontrada', + 'producto_id' => $producto?->id, + 'producto_nombre' => $producto?->nombre ?? 'No encontrado', + 'variante_id' => $variante?->id, + 'variante_info' => $variante ? $this->getVariantInfo($variante) : null, + 'cantidad' => $cantidad, + 'precio_unitario' => $precio, + 'subtotal' => $subtotal, + 'DetalleCompra' => $row['observaciones'] ?? $row['detalle'] ?? '', + ]; + + return $result; + } + + /** + * Obtiene información formateada de la variante + */ + private function getVariantInfo($variante): string + { + $colorName = $variante->color?->name ?? 'Sin color'; + $sizeName = $variante->size?->name ?? 'Sin talla'; + return "$colorName / $sizeName"; + } + + /** + * Normaliza las claves del array + */ + private function normalizeKeys(array $row): array + { + $normalized = []; + $mappings = [ + 'codigo_de_barras' => 'codigo_barras', + 'codigo' => 'codigo_barras', + 'barcode' => 'codigo_barras', + 'precio' => 'precio_unitario', + 'precio_unit' => 'precio_unitario', + 'observacion' => 'observaciones', + 'detalle' => 'observaciones', + 'cantidad' => 'cantidad', + 'cant' => 'cantidad', + 'qty' => 'cantidad', + 'producto' => 'producto', + 'nombre' => 'producto', + 'nombre_producto' => 'producto', + 'articulo' => 'producto', + 'bodega' => 'bodega', + ]; + + foreach ($row as $key => $value) { + $normalizedKey = strtolower(trim($key)); + $normalizedKey = str_replace(' ', '_', $normalizedKey); + $normalizedKey = $this->removeAccents($normalizedKey); + + if (isset($mappings[$normalizedKey])) { + $normalized[$mappings[$normalizedKey]] = $value; + } else { + $normalized[$normalizedKey] = $value; + } + } + + return $normalized; + } + + /** + * Elimina tildes + */ + private function removeAccents($string) + { + $unwanted = [ + 'á' => 'a', 'é' => 'e', 'í' => 'i', 'ó' => 'o', 'ú' => 'u', + 'Á' => 'A', 'É' => 'E', 'Í' => 'I', 'Ó' => 'O', 'Ú' => 'U', + 'ñ' => 'n', 'Ñ' => 'N', + ]; + return strtr($string, $unwanted); + } + + /** + * Reglas de validación + */ + public function rules(): array + { + return [ + 'codigo_barras' => 'nullable|string', + 'producto' => 'nullable|string', + 'bodega' => 'nullable|string', + 'cantidad' => 'nullable|integer|min:1', + 'precio_unitario' => 'nullable|numeric|min:0', + 'observaciones' => 'nullable|string', + ]; + } + + /** + * Obtiene los datos de vista preliminar + */ + public function getPreviewData(): array + { + return $this->previewData; + } + + /** + * Obtiene estadísticas de la importación + */ + public function getStats(): array + { + $valid = collect($this->previewData)->filter(fn($item) => $item['valid'])->count(); + $invalid = collect($this->previewData)->filter(fn($item) => !$item['valid'])->count(); + $productosCreados = collect($this->previewData)->filter(fn($item) => isset($item['producto_creado']) && $item['producto_creado'])->count(); + $total = count($this->previewData); + $totalAmount = collect($this->previewData) + ->where('valid', true) + ->sum(fn($item) => $item['data']['subtotal']); + + return [ + 'total' => $total, + 'valid' => $valid, + 'invalid' => $invalid, + 'productos_creados' => $productosCreados, + 'total_amount' => $totalAmount, + ]; + } + + /** + * Convierte los datos preliminares a formato para guardar + */ + public function getDetallesForSave(): array + { + return collect($this->previewData) + ->filter(fn($item) => $item['valid']) + ->map(fn($item) => [ + 'bodega_id' => $item['data']['bodega_id'], + 'producto_id' => $item['data']['producto_id'], + 'variante_id' => $item['data']['variante_id'], + 'cantidad' => $item['data']['cantidad'], + 'precio_unitario' => $item['data']['precio_unitario'], + 'subtotal' => $item['data']['subtotal'], + 'DetalleCompra' => $item['data']['DetalleCompra'], + 'producto_nombre_snapshot' => $item['data']['producto_nombre'], + 'variante_info_snapshot' => $item['data']['variante_info'], + ]) + ->toArray(); + } +} diff --git a/app/Imports/ProductosImport.php b/app/Imports/ProductosImport.php new file mode 100644 index 0000000..6b6b7ae --- /dev/null +++ b/app/Imports/ProductosImport.php @@ -0,0 +1,300 @@ + $value) { + $normalizedKey = $this->normalizeColumnName($key); + $normalizedData[$normalizedKey] = $value; + } + $data = $normalizedData; + + // Código de barras a string + if (isset($data['codigo_de_barras']) && is_numeric($data['codigo_de_barras'])) { + $data['codigo_de_barras'] = (string) $data['codigo_de_barras']; + } + + // Estado a string + if (isset($data['estado'])) { + if (is_bool($data['estado']) || is_numeric($data['estado'])) { + $data['estado'] = $data['estado'] ? 'Activo' : 'Inactivo'; + } + } + + // Unidad de medida a string + if (isset($data['unidad_de_medida']) && !is_string($data['unidad_de_medida'])) { + $data['unidad_de_medida'] = (string) $data['unidad_de_medida']; + } + + // Categoría por nombre + if (!empty($data['categoria_nombre']) && empty($data['categoria_id'])) { + $categoria = Categoria::firstOrCreate( + ['nombre' => $data['categoria_nombre']], + ['descripcion' => 'Categoría creada automáticamente durante importación'] + ); + $data['categoria_id'] = $categoria->id; + } + + // Categoría (id o nombre) + if (!empty($data['categoria']) && empty($data['categoria_id'])) { + if (is_numeric($data['categoria'])) { + $data['categoria_id'] = $data['categoria']; + } else { + $categoria = Categoria::firstOrCreate( + ['nombre' => $data['categoria']], + ['descripcion' => 'Categoría creada automáticamente durante importación'] + ); + $data['categoria_id'] = $categoria->id; + } + } + + return $data; + } + + /** + * Normaliza el nombre de una columna. + */ + private function normalizeColumnName($name) + { + $mappings = [ + 'código de barras' => 'codigo_de_barras', + 'codigo de barras' => 'codigo_de_barras', + 'categoría' => 'categoria', + 'categoria' => 'categoria', + 'descripción' => 'descripcion', + 'descripcion' => 'descripcion', + 'unidad de medida' => 'unidad_de_medida', + 'stock mínimo' => 'stock_minimo', + 'stock minimo' => 'stock_minimo', + 'stock máximo' => 'stock_maximo', + 'stock maximo' => 'stock_maximo', + 'precio compra' => 'precio_compra', + 'precio venta' => 'precio_venta', + ]; + $normalized = strtolower(trim($name)); + if (isset($mappings[$normalized])) { + return $mappings[$normalized]; + } + $normalized = str_replace(' ', '_', $normalized); + $normalized = $this->removeAccents($normalized); + return $normalized; + } + + /** + * Elimina tildes. + */ + private function removeAccents($string) + { + $unwanted = [ + 'á' => 'a', 'é' => 'e', 'í' => 'i', 'ó' => 'o', 'ú' => 'u', + 'Á' => 'A', 'É' => 'E', 'Í' => 'I', 'Ó' => 'O', 'Ú' => 'U', + 'ñ' => 'n', 'Ñ' => 'N', + ]; + return strtr($string, $unwanted); + } + + /** + * Obtiene el ID de categoría. + */ + private function getCategoriaId(array $row): ?int + { + if (!empty($row['categoria_id']) && is_numeric($row['categoria_id'])) { + return (int) $row['categoria_id']; + } + if (!empty($row['categoria_nombre'])) { + $cat = Categoria::where('nombre', $row['categoria_nombre'])->first(); + if ($cat) return $cat->id; + } + if (!empty($row['categoria'])) { + if (is_numeric($row['categoria'])) { + return (int) $row['categoria']; + } + $cat = Categoria::where('nombre', $row['categoria'])->first(); + if ($cat) return $cat->id; + } + return null; + } + + /** + * Parsea unidad de medida. + */ + private function parseUnidadMedida($value): string + { + if (empty($value)) return 'unidad'; + $value = strtolower(trim($value)); + $map = [ + 'unidad' => 'unidad', + 'unidades' => 'unidad', + 'u' => 'unidad', + 'docena' => 'docena', + 'docenas' => 'docena', + 'dz' => 'docena', + 'doc' => 'docena', + ]; + return $map[$value] ?? 'unidad'; + } + + /** + * Convierte estado a booleano. + */ + private function parseEstado($value): bool + { + if (is_bool($value)) return $value; + if (is_numeric($value)) return (bool) $value; + $value = strtolower(trim($value)); + return in_array($value, ['activo', 'active', '1', 'true', 'si', 'yes']); + } + + /** + * Crea o actualiza el producto y asigna stock a la bodega. + */ + public function model(array $row) + { + $categoriaId = $this->getCategoriaId($row); + + // Determinar bodega + $bodegaId = null; + if (!empty($row['bodega_id'])) { + $bodegaId = $row['bodega_id']; + } elseif (!empty($row['bodega'])) { + $bodega = Bodega::where('nombre', $row['bodega'])->first(); + $bodegaId = $bodega ? $bodega->id : null; + } else { + $bodega = Bodega::where('nombre', 'Principal')->first(); + $bodegaId = $bodega ? $bodega->id : null; + } + + // Actualizar por ID + if (!empty($row['id']) && is_numeric($row['id'])) { + $producto = Producto::find($row['id']); + if ($producto) { + $producto->update([ + 'nombre' => $row['nombre'], + 'descripcion' => $row['descripcion'] ?? null, + 'codigo_barras' => $row['codigo_de_barras'] ?? null, + 'categoria_id' => $categoriaId, + 'precio_compra' => $row['precio_compra'], + 'precio_venta' => $row['precio_venta'], + 'stock_minimo' => $row['stock_minimo'] ?? null, + 'stock_maximo' => $row['stock_maximo'] ?? null, + 'unidad_medida' => $this->parseUnidadMedida($row['unidad_de_medida'] ?? $row['unidad_medida'] ?? 'unidad'), + 'estado' => $this->parseEstado($row['estado'] ?? 'Activo'), + 'imagen' => '', + ]); + if ($bodegaId && isset($row['stock'])) { + $producto->bodegas()->syncWithoutDetaching([ + $bodegaId => ['stock' => $row['stock']], + ]); + } + return null; + } + } + + // Actualizar por código de barras + if (!empty($row['codigo_de_barras'])) { + $existente = Producto::where('codigo_barras', $row['codigo_de_barras'])->first(); + if ($existente) { + $existente->update([ + 'nombre' => $row['nombre'], + 'descripcion' => $row['descripcion'] ?? null, + 'categoria_id' => $categoriaId, + 'precio_compra' => $row['precio_compra'], + 'precio_venta' => $row['precio_venta'], + 'stock_minimo' => $row['stock_minimo'] ?? null, + 'stock_maximo' => $row['stock_maximo'] ?? null, + 'unidad_medida' => $this->parseUnidadMedida($row['unidad_de_medida'] ?? $row['unidad_medida'] ?? 'unidad'), + 'estado' => $this->parseEstado($row['estado'] ?? 'Activo'), + 'imagen' => '', + ]); + if ($bodegaId && isset($row['stock'])) { + $existente->bodegas()->syncWithoutDetaching([ + $bodegaId => ['stock' => $row['stock']], + ]); + } + return null; + } + } + + // Crear nuevo producto + $producto = new Producto([ + 'nombre' => $row['nombre'], + 'descripcion' => $row['descripcion'] ?? null, + 'codigo_barras' => $row['codigo_de_barras'] ?? null, + 'categoria_id' => $categoriaId, + 'precio_compra' => $row['precio_compra'], + 'precio_venta' => $row['precio_venta'], + 'stock_minimo' => $row['stock_minimo'] ?? null, + 'stock_maximo' => $row['stock_maximo'] ?? null, + 'unidad_medida' => $this->parseUnidadMedida($row['unidad_de_medida'] ?? $row['unidad_medida'] ?? 'unidad'), + 'estado' => $this->parseEstado($row['estado'] ?? 'Activo'), + 'imagen' => '', + ]); + $producto->save(); + if ($bodegaId && isset($row['stock'])) { + $producto->bodegas()->attach($bodegaId, ['stock' => $row['stock']]); + } + return $producto; + } + + /** + * Reglas de validación. + */ + public function rules(): array + { + return [ + 'nombre' => 'required|string|max:255', + 'descripcion' => 'nullable', + 'codigo_de_barras' => 'nullable', + 'categoria_id' => 'required|exists:categorias,id', + 'precio_compra' => 'required|numeric|min:0', + 'precio_venta' => 'required|numeric|min:0', + 'stock' => 'nullable|integer|min:0', + 'stock_minimo' => 'nullable|integer|min:0', + 'stock_maximo' => 'nullable|integer|min:0', + 'unidad_de_medida' => 'nullable', + 'unidad_medida' => 'nullable', + 'estado' => 'nullable', + ]; + } + + /** + * Mensajes personalizados. + */ + public function customValidationMessages() + { + return [ + 'nombre.required' => 'El nombre del producto es obligatorio.', + 'categoria_id.required' => 'La categoría es obligatoria.', + 'categoria_id.exists' => 'La categoría especificada no existe.', + 'precio_compra.required' => 'El precio de compra es obligatorio.', + 'precio_compra.numeric' => 'El precio de compra debe ser un número.', + 'precio_venta.required' => 'El precio de venta es obligatorio.', + 'precio_venta.numeric' => 'El precio de venta debe ser un número.', + 'stock.integer' => 'El stock debe ser un número entero.', + 'unidad_de_medida.in' => 'La unidad de medida debe ser: unidad o docena.', + ]; + } +} diff --git a/app/Mail/AlertaStockMail.php b/app/Mail/AlertaStockMail.php new file mode 100644 index 0000000..6c7ca61 --- /dev/null +++ b/app/Mail/AlertaStockMail.php @@ -0,0 +1,41 @@ +productosStockMinimo = $productosStockMinimo; + $this->productosStockMaximo = $productosStockMaximo; + $this->email = $email; + } + + public function build() + { + $subject = 'Alerta de Stock - '; + + if ($this->productosStockMinimo->isNotEmpty() && $this->productosStockMaximo->isNotEmpty()) { + $subject .= 'Stock Mínimo y Máximo'; + } elseif ($this->productosStockMinimo->isNotEmpty()) { + $subject .= 'Stock Mínimo Alcanzado'; + } else { + $subject .= 'Stock Máximo Excedido'; + } + + return $this->subject($subject) + ->to($this->email) + ->view('emails.alerta-stock'); + } +} \ No newline at end of file diff --git a/app/Mail/ReporteVentasMail.php b/app/Mail/ReporteVentasMail.php new file mode 100644 index 0000000..f3abace --- /dev/null +++ b/app/Mail/ReporteVentasMail.php @@ -0,0 +1,33 @@ +ventas = $ventas; + $this->fromDate = $fromDate; + $this->toDate = $toDate; + $this->email = $email; // Guardamos el correo + } + + public function build() + { + return $this->subject('Reporte de Ventas') + ->to($this->email) // Enviamos el correo a la dirección proporcionada + ->view('emails.reporte-ventas'); + } +} diff --git a/app/Mail/WelcomeUserMail.php b/app/Mail/WelcomeUserMail.php new file mode 100644 index 0000000..b3f31e1 --- /dev/null +++ b/app/Mail/WelcomeUserMail.php @@ -0,0 +1,36 @@ +user = $user; + $this->password = $password; + $this->loginUrl = config('app.url') . '/admin/login'; // URL dinámica + } + + public function build() + { + return $this->subject('Bienvenido a la plataforma') + ->view('emails.welcome-user') + ->with([ + 'name' => $this->user->name, + 'email' => $this->user->email, + 'password' => $this->password, + 'loginUrl' => $this->loginUrl, + ]); + } +} diff --git a/app/Models/Bodega.php b/app/Models/Bodega.php new file mode 100644 index 0000000..df3f864 --- /dev/null +++ b/app/Models/Bodega.php @@ -0,0 +1,68 @@ + 'integer', + ]; + + /** + * Relación many‑to‑many con productos. + */ + public function productos(): BelongsToMany + { + return $this->belongsToMany(Producto::class, 'producto_bodega') + ->withPivot('stock') + ->withTimestamps(); + } + + /** + * Relación many-to-many con variantes. + */ + public function variantes(): BelongsToMany + { + return $this->belongsToMany(ProductVariant::class, 'variante_bodega', 'bodega_id', 'variante_id') + ->withPivot('stock') + ->withTimestamps(); + } + + /** + * Obtener el stock total de todos los productos en esta bodega. + */ + public function getStockTotalAttribute(): int + { + return $this->productos()->sum('producto_bodega.stock'); + } + + /** + * Obtener el stock de un producto específico en esta bodega. + */ + public function getStockProducto(int $productoId): int + { + $producto = $this->productos()->where('producto_id', $productoId)->first(); + return $producto ? $producto->pivot->stock : 0; + } +} \ No newline at end of file diff --git a/app/Models/Caja.php b/app/Models/Caja.php new file mode 100644 index 0000000..b82306b --- /dev/null +++ b/app/Models/Caja.php @@ -0,0 +1,49 @@ + 'integer', + 'monto_inicial' => 'decimal:2', + 'monto_final' => 'decimal:2', + 'fecha_apertura' => 'datetime', + 'fecha_cierre' => 'datetime', + ]; + + public function movimientoscaja() + { + return $this->hasMany(MovimientoCaja::class); + } + // Método para calcular el monto final + public function calcularMontoFinal() + { + $ingresos = $this->movimientoscaja()->where('tipo', 'Ingreso')->sum('monto'); + $egresos = $this->movimientoscaja()->where('tipo', 'Egreso')->sum('monto'); + return $this->monto_inicial + $ingresos - $egresos; + } +} diff --git a/app/Models/Categoria.php b/app/Models/Categoria.php new file mode 100644 index 0000000..7a9cf6c --- /dev/null +++ b/app/Models/Categoria.php @@ -0,0 +1,30 @@ + 'integer', + ]; +} diff --git a/app/Models/Cliente.php b/app/Models/Cliente.php new file mode 100644 index 0000000..e14919e --- /dev/null +++ b/app/Models/Cliente.php @@ -0,0 +1,32 @@ + 'integer', + ]; +} diff --git a/app/Models/Color.php b/app/Models/Color.php new file mode 100644 index 0000000..515018f --- /dev/null +++ b/app/Models/Color.php @@ -0,0 +1,30 @@ + 'integer', + ]; +} diff --git a/app/Models/Compra.php b/app/Models/Compra.php new file mode 100644 index 0000000..8469ff3 --- /dev/null +++ b/app/Models/Compra.php @@ -0,0 +1,60 @@ + 'integer', + 'fecha' => 'datetime', + 'proveedor_id' => 'integer', + 'total' => 'decimal:2', + ]; + + public function proveedor(): BelongsTo + { + return $this->belongsTo(Proveedor::class); + } + + public function detalles() + { + return $this->hasMany(DetalleCompra::class); + } + + /** + * Boot del modelo para eventos + */ + protected static function boot() + { + parent::boot(); + + // Al eliminar una compra, eliminar sus detalles + static::deleting(function ($compra) { + $compra->detalles()->delete(); + }); + } + +} diff --git a/app/Models/DetalleCompra.php b/app/Models/DetalleCompra.php new file mode 100644 index 0000000..b4bb34c --- /dev/null +++ b/app/Models/DetalleCompra.php @@ -0,0 +1,94 @@ + 'integer', + 'compra_id' => 'integer', + 'producto_id' => 'integer', + 'variante_id' => 'integer', + 'bodega_id' => 'integer', + 'cantidad'=> 'integer', + 'precio_unitario' => 'decimal:2', + 'subtotal' => 'decimal:2', + ]; + + public function compra(): BelongsTo + { + return $this->belongsTo(Compra::class); + } + + public function producto(): BelongsTo + { + return $this->belongsTo(Producto::class)->withDefault(); + } + + public function variante():BelongsTo + { + return $this->belongsTo(ProductVariant::class)->withDefault(); + } + + public function bodega(): BelongsTo + { + return $this->belongsTo(Bodega::class); + } + + /** + * Obtiene el nombre del producto, usando snapshot si el producto fue eliminado + */ + public function getProductoNombreAttribute(): string + { + if ($this->producto) { + return $this->producto->nombre; + } + + return $this->producto_nombre_snapshot ?? 'Producto eliminado'; + } + + /** + * Obtiene la información de la variante, usando snapshot si la variante fue eliminada + */ + public function getVarianteInfoAttribute(): ?string + { + if ($this->variante) { + // Validación defensiva para evitar error "name" on null + $colorName = $this->variante->color ? $this->variante->color->name : 'Sin color'; + $sizeName = $this->variante->size ? $this->variante->size->name : 'Sin talla'; + + return $colorName . ' / ' . $sizeName; + } + + return $this->variante_info_snapshot; + } +} diff --git a/app/Models/DetalleVenta.php b/app/Models/DetalleVenta.php new file mode 100644 index 0000000..b7f7b72 --- /dev/null +++ b/app/Models/DetalleVenta.php @@ -0,0 +1,62 @@ + 'integer', + 'venta_id' => 'integer', + 'producto_id' => 'integer', + 'precio_unitario' => 'decimal:2', + 'subtotal' => 'decimal:2', + ]; + + public function venta(): BelongsTo + { + return $this->belongsTo(Venta::class); + } + + public function producto(): BelongsTo + { + return $this->belongsTo(Producto::class); + } + + + public function variante(): BelongsTo + { + return $this->belongsTo(ProductVariant::class); + } + + public function bodega(): BelongsTo + { + return $this->belongsTo(Bodega::class); + } +} diff --git a/app/Models/Inventario.php b/app/Models/Inventario.php new file mode 100644 index 0000000..8fb89e7 --- /dev/null +++ b/app/Models/Inventario.php @@ -0,0 +1,39 @@ + 'integer', + 'producto_id' => 'integer', + ]; + + public function producto(): BelongsTo + { + return $this->belongsTo(Producto::class); + } +} diff --git a/app/Models/MovimientoCaja.php b/app/Models/MovimientoCaja.php new file mode 100644 index 0000000..cf35ebb --- /dev/null +++ b/app/Models/MovimientoCaja.php @@ -0,0 +1,41 @@ + 'integer', + 'caja_id' => 'integer', + 'monto' => 'decimal:2', + ]; + + public function caja(): BelongsTo + { + return $this->belongsTo(Caja::class); + } +} diff --git a/app/Models/Permission.php b/app/Models/Permission.php new file mode 100644 index 0000000..8aef4cb --- /dev/null +++ b/app/Models/Permission.php @@ -0,0 +1,24 @@ + 'web', // Establece el valor predeterminado + ]; + + public function roles() + { + return $this->belongsToMany(Role::class, 'role_has_permissions'); + } + +} diff --git a/app/Models/ProductVariant.php b/app/Models/ProductVariant.php new file mode 100644 index 0000000..e1b5bf6 --- /dev/null +++ b/app/Models/ProductVariant.php @@ -0,0 +1,93 @@ + 'integer', + ]; + + public function producto(): BelongsTo + { + return $this->belongsTo(Producto::class); + } + + public function color(): BelongsTo + { + return $this->belongsTo(Color::class); + } + + public function size(): BelongsTo + { + return $this->belongsTo(Size::class); + } + + /** + * Relación many-to-many con bodegas + */ + public function bodegas(): BelongsToMany + { + return $this->belongsToMany(Bodega::class, 'variante_bodega', 'variante_id', 'bodega_id') + ->withPivot('stock') + ->withTimestamps(); + } + + /** + * Obtener el stock total de la variante en todas las bodegas + */ + public function getStockTotalBodegas(): int + { + try { + return $this->bodegas()->sum('variante_bodega.stock'); + } catch (\Exception $e) { + // En caso de error, retornar 0 + return 0; + } + } + + /** + * Obtener el stock efectivo de la variante (considerando bodegas si existen) + */ + public function getStockEfectivo(): int + { + try { + // Si tiene distribución en bodegas, usar ese stock + if ($this->bodegas()->exists()) { + return $this->getStockTotalBodegas(); + } + } catch (\Exception $e) { + // En caso de error (tabla no existe, etc.), usar stock directo + // Esto puede ocurrir durante migraciones o configuración inicial + } + + // Stock directo de la variante + return $this->stock; + } +} diff --git a/app/Models/Producto.php b/app/Models/Producto.php new file mode 100644 index 0000000..6e57fc6 --- /dev/null +++ b/app/Models/Producto.php @@ -0,0 +1,256 @@ + 'integer', + 'estado' => 'boolean', + ]; + + public function variants(): HasMany + { + return $this->hasMany(ProductVariant::class); + } + public function categoria(): BelongsTo + { + return $this->belongsTo(Categoria::class); + } + + /** + * Relación many-to-many con bodegas + */ + public function bodegas(): BelongsToMany + { + return $this->belongsToMany(Bodega::class, 'producto_bodega') + ->withPivot('stock') + ->withTimestamps(); + } + + /** + * Obtiene las unidades de medida disponibles + */ + public static function getUnidadesMedida(): array + { + return [ + 'unidad' => 'Unidad (1)', + 'docena' => 'Docena (12)', + ]; + } + + /** + * Obtiene el factor de conversión para una unidad de medida + */ + public static function getFactorConversion(string $unidad): int + { + $factores = [ + 'unidad' => 1, + 'docena' => 12, + ]; + + return $factores[$unidad] ?? 1; + } + + /** + * Convierte una cantidad en la unidad especificada a unidades individuales + */ + public static function convertirAUnidades(float $cantidad, string $unidad): int + { + return (int) ($cantidad * self::getFactorConversion($unidad)); + } + + /** + * Convierte unidades individuales a la unidad de medida especificada + */ + public static function convertirDesdeUnidades(int $unidades, string $unidad): float + { + $factor = self::getFactorConversion($unidad); + return $factor > 1 ? round($unidades / $factor, 2) : $unidades; + } + + /** + * Obtiene el stock en la unidad de medida configurada + */ + public function getStockEnUnidadMedida(): float + { + $stockTotal = $this->variants()->exists() + ? $this->variants()->sum('stock') + : $this->stock; + + return self::convertirDesdeUnidades($stockTotal, $this->unidad_medida ?? 'unidad'); + } + + /** + * Obtiene el nombre de la unidad de medida + */ + public function getNombreUnidadMedida(): string + { + $unidades = self::getUnidadesMedida(); + return $unidades[$this->unidad_medida ?? 'unidad'] ?? 'Unidad (1)'; + } + + /** + * Obtener el stock total en todas las bodegas + */ + public function getStockTotalBodegas(): int + { + return $this->bodegas()->sum('producto_bodega.stock'); + } + + /** + * Obtener el stock en una bodega específica + */ + public function getStockEnBodega(int $bodegaId): int + { + $bodega = $this->bodegas()->where('bodega_id', $bodegaId)->first(); + return $bodega ? $bodega->pivot->stock : 0; + } + + /** + * Obtener el stock total en una bodega específica (considerando variantes) + */ + public function getStockTotalEnBodega(int $bodegaId): int + { + if ($this->variants()->exists()) { + $stockVariantes = 0; + foreach ($this->variants as $variante) { + $bodegaVariante = $variante->bodegas()->where('bodega_id', $bodegaId)->first(); + if ($bodegaVariante) { + $stockVariantes += $bodegaVariante->pivot->stock; + } + } + return $stockVariantes; + } else { + return $this->getStockEnBodega($bodegaId); + } + } + + /** + * Distribuir stock total entre bodegas + */ + public function distribuirStock(array $distribucion): void + { + foreach ($distribucion as $bodegaId => $stock) { + $this->bodegas()->syncWithoutDetaching([ + $bodegaId => ['stock' => $stock] + ]); + } + } + + /** + * Obtener el stock efectivo (considerando bodegas Y variantes correctamente) + */ + public function getStockEfectivo(): int + { + // Si tiene variantes, el stock se calcula desde las variantes + if ($this->variants()->exists()) { + $stockVariantes = 0; + + foreach ($this->variants as $variante) { + $stockVariantes += $variante->getStockEfectivo(); + } + + return $stockVariantes; + } else { + // Para productos sin variantes + if ($this->bodegas()->exists()) { + return $this->getStockTotalBodegas(); + } else { + return $this->stock; + } + } + } + + /** + * Accessor para código de barras dinámico + */ + public function getCodigoBarrasAttribute($value) + { + // Si el producto tiene variantes, el código de barras es NULL + if ($this->variants()->exists()) { + return null; + } + + // Si NO tiene variantes, usa su código de barras propio + return $value; + } + + /** + * Accessor para stock dinámico + * Si el producto tiene variantes, el stock directo debe ser 0 + */ + public function getStockAttribute($value) + { + // Si el producto tiene variantes, el stock directo debe ser 0 + if ($this->variants()->exists()) { + return 0; + } + + // Si NO tiene variantes, devuelve el stock real + return $value; + } + + /** + * Mutator para stock - evita que se asigne stock directo si hay variantes + */ + public function setStockAttribute($value) + { + // Si el producto ya tiene variantes, no permitir stock directo + if ($this->exists && $this->variants()->exists()) { + $this->attributes['stock'] = 0; + } else { + $this->attributes['stock'] = $value; + } + } + + /** + * Relación con detalles de compra + */ + public function detalleCompras(): HasMany + { + return $this->hasMany(DetalleCompra::class); + } + + /** + * Relación con detalles de venta + */ + public function detalleVentas(): HasMany + { + return $this->hasMany(DetalleVenta::class); + } +} diff --git a/app/Models/Proveedor.php b/app/Models/Proveedor.php new file mode 100644 index 0000000..78c4c0c --- /dev/null +++ b/app/Models/Proveedor.php @@ -0,0 +1,33 @@ + 'integer', + ]; +} diff --git a/app/Models/Role.php b/app/Models/Role.php new file mode 100644 index 0000000..502601d --- /dev/null +++ b/app/Models/Role.php @@ -0,0 +1,45 @@ + 'integer', + ]; + + /** + * Get the users that belong to the role. + */ + public function users(): BelongsToMany + { + return $this->belongsToMany(User::class, 'model_has_roles', 'role_id', 'model_id'); + } + public function permissions(): BelongsToMany + { + return $this->belongsToMany(Permission::class); + } +} \ No newline at end of file diff --git a/app/Models/Setting.php b/app/Models/Setting.php new file mode 100644 index 0000000..3113c8f --- /dev/null +++ b/app/Models/Setting.php @@ -0,0 +1,34 @@ + 'integer', + 'created_at' => 'timestamp', + 'updated_at' => 'timestamp', + ]; +} diff --git a/app/Models/Size.php b/app/Models/Size.php new file mode 100644 index 0000000..1d86d9b --- /dev/null +++ b/app/Models/Size.php @@ -0,0 +1,29 @@ + 'integer', + ]; +} diff --git a/app/Models/TransferenciaBodega.php b/app/Models/TransferenciaBodega.php new file mode 100644 index 0000000..adcbeaf --- /dev/null +++ b/app/Models/TransferenciaBodega.php @@ -0,0 +1,69 @@ + 'datetime', + ]; + + /** + * Relación con el producto + */ + public function producto(): BelongsTo + { + return $this->belongsTo(Producto::class); + } + + /** + * Relación con la variante (opcional) + */ + public function variante(): BelongsTo + { + return $this->belongsTo(ProductVariant::class, 'variante_id'); + } + + /** + * Relación con la bodega de origen + */ + public function bodegaOrigen(): BelongsTo + { + return $this->belongsTo(Bodega::class, 'bodega_origen_id'); + } + + /** + * Relación con la bodega de destino + */ + public function bodegaDestino(): BelongsTo + { + return $this->belongsTo(Bodega::class, 'bodega_destino_id'); + } + + /** + * Relación con el usuario que realizó la transferencia + */ + public function usuario(): BelongsTo + { + return $this->belongsTo(User::class, 'usuario_id'); + } +} \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php new file mode 100644 index 0000000..5fb63b8 --- /dev/null +++ b/app/Models/User.php @@ -0,0 +1,57 @@ + 'datetime', + 'password' => 'hashed', // Laravel 10+ soporta casting a hashed + ]; + + /** + * Get the roles associated with the user. + */ + public function roles(): BelongsToMany + { + return $this->belongsToMany(Role::class); + } + + +} diff --git a/app/Models/Venta.php b/app/Models/Venta.php new file mode 100644 index 0000000..6af423f --- /dev/null +++ b/app/Models/Venta.php @@ -0,0 +1,48 @@ + 'integer', + 'fecha' => 'datetime', + 'cliente_id' => 'integer', + 'total' => 'decimal:2', + ]; + + public function cliente(): BelongsTo + { + return $this->belongsTo(Cliente::class); + } + + public function detalles(): HasMany + { + return $this->hasMany(DetalleVenta::class); + } +} diff --git a/app/Notifications/StockMinimoNotificacion.php b/app/Notifications/StockMinimoNotificacion.php new file mode 100644 index 0000000..2c006bd --- /dev/null +++ b/app/Notifications/StockMinimoNotificacion.php @@ -0,0 +1,35 @@ +producto = $producto; + } + + public function via(object $notifiable): array + { + return ['mail']; + } + + public function toMail(object $notifiable): MailMessage + { + return (new MailMessage) + ->subject('⚠️ Stock mínimo alcanzado') + ->line("El producto '{$this->producto->nombre}' ha alcanzado el stock mínimo.") + ->line("Stock actual: {$this->producto->stock}") + ->line("Stock mínimo: {$this->producto->stock_minimo}") + ->action('Ver producto', url("/admin/productos/{$this->producto->id}/edit")); // Ajusta ruta si usas Filament + } +} diff --git a/app/Observers/CompraObserver.php b/app/Observers/CompraObserver.php new file mode 100644 index 0000000..0ea6f4f --- /dev/null +++ b/app/Observers/CompraObserver.php @@ -0,0 +1,171 @@ +isDirty('estado') && $compra->estado === 'Recibida') { + Log::info("Procesando compra recibida", [ + 'compra_id' => $compra->id, + 'detalles_count' => $compra->detalles->count() + ]); + + DB::beginTransaction(); + + try { + foreach ($compra->detalles as $detalle) { + Log::info("Procesando detalle de compra", [ + 'detalle_id' => $detalle->id, + 'producto_id' => $detalle->producto_id, + 'variante_id' => $detalle->variante_id, + 'bodega_id' => $detalle->bodega_id, + 'cantidad' => $detalle->cantidad + ]); + + if ($detalle->variante_id) { + // Manejo para variantes + $variante = ProductVariant::find($detalle->variante_id); + if ($variante && $detalle->bodega_id) { + // Actualizar stock en bodega para la variante + $existeRelacion = $variante->bodegas() + ->where('bodega_id', $detalle->bodega_id) + ->exists(); + + if ($existeRelacion) { + // Incrementar stock existente + $pivotData = $variante->bodegas() + ->where('bodega_id', $detalle->bodega_id) + ->first(); + + $nuevoStock = $pivotData->pivot->stock + $detalle->cantidad; + + $variante->bodegas()->updateExistingPivot($detalle->bodega_id, [ + 'stock' => $nuevoStock + ]); + } else { + // Crear nueva relación con stock + $variante->bodegas()->attach($detalle->bodega_id, [ + 'stock' => $detalle->cantidad + ]); + } + + Log::info("Stock actualizado para variante en bodega", [ + 'variante_id' => $variante->id, + 'bodega_id' => $detalle->bodega_id, + 'cantidad_agregada' => $detalle->cantidad + ]); + } else { + // Fallback: incrementar stock directo de la variante si no hay bodega especificada + ProductVariant::where('id', $detalle->variante_id) + ->increment('stock', $detalle->cantidad); + + Log::info("Stock incrementado directamente en variante (sin bodega)", [ + 'variante_id' => $detalle->variante_id, + 'cantidad' => $detalle->cantidad + ]); + } + } else { + // Manejo para productos sin variantes + $producto = Producto::find($detalle->producto_id); + if ($producto && $detalle->bodega_id) { + // Actualizar stock en bodega para el producto + $existeRelacion = $producto->bodegas() + ->where('bodega_id', $detalle->bodega_id) + ->exists(); + + if ($existeRelacion) { + // Incrementar stock existente + $pivotData = $producto->bodegas() + ->where('bodega_id', $detalle->bodega_id) + ->first(); + + $nuevoStock = $pivotData->pivot->stock + $detalle->cantidad; + + $producto->bodegas()->updateExistingPivot($detalle->bodega_id, [ + 'stock' => $nuevoStock + ]); + } else { + // Crear nueva relación con stock + $producto->bodegas()->attach($detalle->bodega_id, [ + 'stock' => $detalle->cantidad + ]); + } + + Log::info("Stock actualizado para producto en bodega", [ + 'producto_id' => $producto->id, + 'bodega_id' => $detalle->bodega_id, + 'cantidad_agregada' => $detalle->cantidad + ]); + } else { + // Fallback: incrementar stock directo del producto si no hay bodega especificada + Producto::where('id', $detalle->producto_id) + ->increment('stock', $detalle->cantidad); + + Log::info("Stock incrementado directamente en producto (sin bodega)", [ + 'producto_id' => $detalle->producto_id, + 'cantidad' => $detalle->cantidad + ]); + } + } + } + + DB::commit(); + Log::info("Compra procesada exitosamente", ['compra_id' => $compra->id]); + + } catch (\Exception $e) { + DB::rollback(); + Log::error("Error al procesar compra recibida", [ + 'compra_id' => $compra->id, + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString() + ]); + throw $e; + } + } + } + + /** + * Handle the Compra "deleted" event. + */ + public function deleted(Compra $compra): void + { + // + } + + /** + * Handle the Compra "restored" event. + */ + public function restored(Compra $compra): void + { + // + } + + /** + * Handle the Compra "force deleted" event. + */ + public function forceDeleted(Compra $compra): void + { + // + } +} diff --git a/app/Observers/DetalleCompraObserver.php b/app/Observers/DetalleCompraObserver.php new file mode 100644 index 0000000..b1b0caa --- /dev/null +++ b/app/Observers/DetalleCompraObserver.php @@ -0,0 +1,41 @@ +producto && empty($detalle->producto_nombre_snapshot)) { + $detalle->producto_nombre_snapshot = $detalle->producto->nombre; + + Log::info("Snapshot de producto guardado", [ + 'detalle_id' => $detalle->id, + 'producto_id' => $detalle->producto_id, + 'producto_nombre' => $detalle->producto_nombre_snapshot + ]); + } + + // Guardar snapshot de variante si existe y no hay snapshot previo + if ($detalle->variante && empty($detalle->variante_info_snapshot)) { + // Validación defensiva para evitar error "name" on null + $colorName = $detalle->variante->color ? $detalle->variante->color->name : 'Sin color'; + $sizeName = $detalle->variante->size ? $detalle->variante->size->name : 'Sin talla'; + + $detalle->variante_info_snapshot = $colorName . ' / ' . $sizeName; + + Log::info("Snapshot de variante guardado", [ + 'detalle_id' => $detalle->id, + 'variante_id' => $detalle->variante_id, + 'variante_info' => $detalle->variante_info_snapshot + ]); + } + } +} \ No newline at end of file diff --git a/app/Observers/ProductVariantObserver.php b/app/Observers/ProductVariantObserver.php new file mode 100644 index 0000000..3b31843 --- /dev/null +++ b/app/Observers/ProductVariantObserver.php @@ -0,0 +1,66 @@ +producto; + + Log::info("Variante creada para producto", [ + 'variante_id' => $variant->id, + 'producto_id' => $producto->id, + 'producto_nombre' => $producto->nombre, + 'stock_producto_anterior' => $producto->stock + ]); + + // Si este producto ahora tiene variantes y tenía stock directo, limpiar el stock principal + if ($producto->stock > 0) { + // Obtener el stock anterior para potencial transferencia + $stockAnterior = $producto->stock; + + // Limpiar el stock del producto principal + $producto->update(['stock' => 0]); + + Log::info("Stock del producto principal limpiado debido a creación de variantes", [ + 'producto_id' => $producto->id, + 'stock_anterior' => $stockAnterior, + 'stock_nuevo' => 0 + ]); + + // Opcionalmente, podrías transferir el stock anterior a la nueva variante + // o a una bodega específica, pero por ahora solo lo eliminamos + } + } + + /** + * Handle the ProductVariant "deleting" event. + */ + public function deleting(ProductVariant $variant): void + { + $producto = $variant->producto; + + // Verificar si esta es la última variante + $variantesRestantes = $producto->variants()->where('id', '!=', $variant->id)->count(); + + Log::info("Eliminando variante", [ + 'variante_id' => $variant->id, + 'producto_id' => $producto->id, + 'variantes_restantes' => $variantesRestantes + ]); + + // Si esta era la última variante, el producto vuelve a poder tener stock directo + if ($variantesRestantes === 0) { + Log::info("Última variante eliminada - producto puede volver a tener stock directo", [ + 'producto_id' => $producto->id + ]); + } + } +} \ No newline at end of file diff --git a/app/Observers/ProductoObserver.php b/app/Observers/ProductoObserver.php new file mode 100644 index 0000000..55689a5 --- /dev/null +++ b/app/Observers/ProductoObserver.php @@ -0,0 +1,69 @@ +wasRecentlyCreated) { + return; + } + + $stockActual = $producto->getStockEfectivo(); + + $alertaStockMinimo = collect(); + $alertaStockMaximo = collect(); + + // Verificar stock mínimo + if ($stockActual <= $producto->stock_minimo && $producto->stock_minimo > 0) { + $alertaStockMinimo->push($producto); + Log::info("Stock mínimo alcanzado para producto: {$producto->nombre} (Stock: {$stockActual})"); + } + + // Verificar stock máximo + if ($producto->stock_maximo && $stockActual > $producto->stock_maximo) { + $alertaStockMaximo->push($producto); + Log::info("Stock máximo excedido para producto: {$producto->nombre} (Stock: {$stockActual})"); + } + + // Enviar alertas si hay productos que requieren atención + if ($alertaStockMinimo->isNotEmpty() || $alertaStockMaximo->isNotEmpty()) { + $this->enviarAlertasStock($alertaStockMinimo, $alertaStockMaximo); + } + } + + private function enviarAlertasStock($productosStockMinimo, $productosStockMaximo) + { + // Obtener todos los usuarios con el rol 'Administrador' + $administradores = User::role('Administrador')->get(); + + if ($administradores->isEmpty()) { + Log::warning('No se encontraron usuarios con el rol Administrador para enviar alertas de stock.'); + return; + } + + foreach ($administradores as $admin) { + try { + // Enviar usando el nuevo sistema de alertas + Mail::to($admin->email)->send(new AlertaStockMail( + $productosStockMinimo, + $productosStockMaximo, + $admin->email + )); + + Log::info("Alerta de stock enviada a: {$admin->email}"); + } catch (\Exception $e) { + Log::error("Error al enviar alerta de stock a {$admin->email}: " . $e->getMessage()); + } + } + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..957ca2d --- /dev/null +++ b/app/Providers/AppServiceProvider.php @@ -0,0 +1,67 @@ +app->singleton(EAN13Service::class, function ($app) { + return new EAN13Service(); + }); + } + + /** + * Bootstrap any application services. + */ + public function boot(): void + { + app()->setLocale('es'); + + Compra::observe(CompraObserver::class); + Producto::observe(ProductoObserver::class); + ProductVariant::observe(ProductVariantObserver::class); + DetalleCompra::observe(DetalleCompraObserver::class); + + // Usar el hasher personalizado para todo el sistema + Hash::extend('custom', function () { + return new PBKDF2Hasher(); + }); + + if (Schema::hasTable('settings')) { + try { + $setting = Setting::first(); + if ($setting) { + // Aquí se actualizan los valores de configuración de Filament + Config::set('filament.brand.logo', $setting->logo ? Storage::url($setting->logo) : null); + Config::set('filament.brand.colors.primary', $setting->primary_color ?? '#3498db'); + Config::set('filament.brand.colors.secondary', $setting->secondary_color ?? '#2ecc71'); + } + } catch (\Exception $e) { + Log::error('Error al cargar configuraciones de settings: ' . $e->getMessage()); + } + } + } + +} diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php new file mode 100644 index 0000000..4f28f64 --- /dev/null +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -0,0 +1,60 @@ +default() + ->id('admin') + ->path('admin') + ->login() + ->colors([ + 'primary' => Color::Amber, + ]) + ->discoverResources(in: app_path('Filament/Resources'), for: 'App\\Filament\\Resources') + ->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages') + ->pages([ + Pages\Dashboard::class, + ReporteVentas::class, // <--- registra aquí + ]) + ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets') + ->widgets([ + Widgets\AccountWidget::class, + // Widgets\FilamentInfoWidget::class, + ]) + ->middleware([ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + AuthenticateSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, + DisableBladeIconComponents::class, + DispatchServingFilamentEvent::class, + ]) + ->authMiddleware([ + Authenticate::class, + ]); + } +} diff --git a/app/Services/EAN13Service.php b/app/Services/EAN13Service.php new file mode 100644 index 0000000..4c73ffa --- /dev/null +++ b/app/Services/EAN13Service.php @@ -0,0 +1,85 @@ +calculateCheckDigit($barcodeBase); + $barcode = $barcodeBase . $checkDigit; + + // Verificar si el código de barras ya existe en la base de datos + $existsInProductVariant = ProductVariant::where('barcode', $barcode)->exists(); + $existsInProducto = Producto::where('codigo_barras', $barcode)->exists(); + + if (!$existsInProductVariant && !$existsInProducto) { + // Si no existe, asignar el código único y salir del ciclo + $uniqueBarcode = $barcode; + break; + } + + // Si existe, modificar el código base agregando un sufijo incremental + $suffix = str_pad($attempt, 3, '0', STR_PAD_LEFT); // Agregar un sufijo de 3 dígitos + $barcodeBase = substr($barcodeBase, 0, -3) . $suffix; // Reemplazar los últimos 3 dígitos con el sufijo + } + + // Retornar el código único si se encontró, o null si no se pudo generar + return $uniqueBarcode; + } + + /** + * Calcula el dígito de control de un código EAN-13. + * + * @param string $barcodeBase Los primeros 12 dígitos del código EAN-13 + * @return int Dígito de control calculado + * @throws \Exception Si el código base no tiene 12 caracteres + */ + private function calculateCheckDigit($barcodeBase) + { + if (strlen($barcodeBase) !== 12) { + throw new \Exception("Error: El código base para el dígito de control no tiene 12 caracteres: $barcodeBase"); + } + + $sum = 0; + for ($i = 0; $i < 12; $i++) { + $digit = (int) $barcodeBase[$i]; + $sum += ($i % 2 === 0) ? $digit : $digit * 3; + } + + $remainder = $sum % 10; + return ($remainder === 0) ? 0 : 10 - $remainder; + } +} diff --git a/app/Services/TransferenciaBodegaService.php b/app/Services/TransferenciaBodegaService.php new file mode 100644 index 0000000..2c3f3cc --- /dev/null +++ b/app/Services/TransferenciaBodegaService.php @@ -0,0 +1,375 @@ +obtenerStockEnBodega($producto, $bodegaOrigen); + + if ($stockOrigen < $cantidad) { + throw new Exception( + "Stock insuficiente en {$bodegaOrigen->nombre}. " . + "Disponible: {$stockOrigen}, Solicitado: {$cantidad}" + ); + } + + // Reducir stock en bodega origen + $this->actualizarStockBodega($producto, $bodegaOrigen, $stockOrigen - $cantidad); + + // Aumentar stock en bodega destino + $stockDestino = $this->obtenerStockEnBodega($producto, $bodegaDestino); + $this->actualizarStockBodega($producto, $bodegaDestino, $stockDestino + $cantidad); + + // Crear registro de transferencia + $transferencia = TransferenciaBodega::create([ + 'producto_id' => $productoId, + 'bodega_origen_id' => $bodegaOrigenId, + 'bodega_destino_id' => $bodegaDestinoId, + 'cantidad' => $cantidad, + 'motivo' => $motivo, + 'usuario_id' => Auth::id() ?? 1, // Fallback a usuario administrador si no hay autenticación + 'fecha_transferencia' => now(), + ]); + + DB::commit(); + + return $transferencia; + + } catch (Exception $e) { + DB::rollBack(); + throw $e; + } + } + + /** + * Obtener el stock de un producto en una bodega específica + * + * @param Producto $producto + * @param Bodega $bodega + * @return int + */ + private function obtenerStockEnBodega(Producto $producto, Bodega $bodega): int + { + $relacion = $producto->bodegas()->where('bodega_id', $bodega->id)->first(); + return $relacion ? $relacion->pivot->stock : 0; + } + + /** + * Actualizar el stock de un producto en una bodega + * + * @param Producto $producto + * @param Bodega $bodega + * @param int $nuevoStock + * @return void + */ + private function actualizarStockBodega(Producto $producto, Bodega $bodega, int $nuevoStock): void + { + $existeRelacion = $producto->bodegas()->where('bodega_id', $bodega->id)->exists(); + + if ($existeRelacion) { + // Actualizar relación existente + $producto->bodegas()->updateExistingPivot($bodega->id, [ + 'stock' => $nuevoStock + ]); + } else { + // Crear nueva relación (solo si el stock es mayor a 0) + if ($nuevoStock > 0) { + $producto->bodegas()->attach($bodega->id, [ + 'stock' => $nuevoStock + ]); + } + } + } + + /** + * Obtener el historial de transferencias de un producto + * + * @param int $productoId + * @param int $limit + * @return \Illuminate\Database\Eloquent\Collection + */ + public function obtenerHistorialTransferencias(int $productoId, int $limit = 50) + { + return TransferenciaBodega::with(['bodegaOrigen', 'bodegaDestino', 'usuario']) + ->where('producto_id', $productoId) + ->orderBy('fecha_transferencia', 'desc') + ->limit($limit) + ->get(); + } + + /** + * Obtener resumen de stock por bodega para un producto + * + * @param int $productoId + * @return array + */ + public function obtenerResumenStockPorBodega(int $productoId): array + { + $producto = Producto::with('bodegas')->findOrFail($productoId); + + $resumen = []; + foreach ($producto->bodegas as $bodega) { + $resumen[] = [ + 'bodega_id' => $bodega->id, + 'bodega_nombre' => $bodega->nombre, + 'stock' => $bodega->pivot->stock, + ]; + } + + return $resumen; + } + + /** + * Obtener resumen de stock considerando variantes + * + * @param int $productoId + * @return array + */ + public function obtenerResumenStockCompleto(int $productoId): array + { + $producto = Producto::with(['bodegas', 'variants.bodegas'])->findOrFail($productoId); + + $resumen = [ + 'producto' => [ + 'id' => $producto->id, + 'nombre' => $producto->nombre, + 'tiene_variantes' => $producto->variants()->exists(), + 'stock_efectivo' => $producto->getStockEfectivo(), + ], + 'distribuciones' => [] + ]; + + if ($producto->variants()->exists()) { + // Producto con variantes + foreach ($producto->variants as $variante) { + $stockVariante = $variante->getStockEfectivo(); + + $distribucionVariante = [ + 'variante_id' => $variante->id, + 'sku' => $variante->sku, + 'stock_total' => $stockVariante, + 'bodegas' => [] + ]; + + if ($variante->bodegas()->exists()) { + foreach ($variante->bodegas as $bodega) { + $distribucionVariante['bodegas'][] = [ + 'bodega_id' => $bodega->id, + 'bodega_nombre' => $bodega->nombre, + 'stock' => $bodega->pivot->stock, + ]; + } + } else { + // Stock directo de la variante + $distribucionVariante['stock_directo'] = $variante->stock; + } + + $resumen['distribuciones'][] = $distribucionVariante; + } + } else { + // Producto sin variantes + if ($producto->bodegas()->exists()) { + foreach ($producto->bodegas as $bodega) { + $resumen['distribuciones'][] = [ + 'bodega_id' => $bodega->id, + 'bodega_nombre' => $bodega->nombre, + 'stock' => $bodega->pivot->stock, + ]; + } + } else { + $resumen['stock_directo'] = $producto->stock; + } + } + + return $resumen; + } + + /** + * Transferir variantes entre bodegas + * + * @param int $varianteId + * @param int $bodegaOrigenId + * @param int $bodegaDestinoId + * @param int $cantidad + * @param string|null $motivo + * @return TransferenciaBodega + * @throws Exception + */ + public function transferirVariante( + int $varianteId, + int $bodegaOrigenId, + int $bodegaDestinoId, + int $cantidad, + ?string $motivo = null + ): TransferenciaBodega { + + if ($cantidad <= 0) { + throw new Exception('La cantidad debe ser mayor a 0'); + } + + if ($bodegaOrigenId === $bodegaDestinoId) { + throw new Exception('La bodega de origen y destino no pueden ser la misma'); + } + + $variante = ProductVariant::findOrFail($varianteId); + $bodegaOrigen = Bodega::findOrFail($bodegaOrigenId); + $bodegaDestino = Bodega::findOrFail($bodegaDestinoId); + + DB::beginTransaction(); + + try { + // Verificar que la bodega origen tiene suficiente stock + $stockOrigen = $this->obtenerStockVarianteEnBodega($variante, $bodegaOrigen); + + if ($stockOrigen < $cantidad) { + throw new Exception( + "Stock insuficiente en {$bodegaOrigen->nombre}. " . + "Disponible: {$stockOrigen}, Solicitado: {$cantidad}" + ); + } + + // Reducir stock en bodega origen + $this->actualizarStockVarianteBodega($variante, $bodegaOrigen, $stockOrigen - $cantidad); + + // Aumentar stock en bodega destino + $stockDestino = $this->obtenerStockVarianteEnBodega($variante, $bodegaDestino); + $this->actualizarStockVarianteBodega($variante, $bodegaDestino, $stockDestino + $cantidad); + + // Crear registro de transferencia + $transferencia = TransferenciaBodega::create([ + 'variante_id' => $varianteId, + 'producto_id' => $variante->producto_id, + 'bodega_origen_id' => $bodegaOrigenId, + 'bodega_destino_id' => $bodegaDestinoId, + 'cantidad' => $cantidad, + 'motivo' => $motivo ? "Variante: {$motivo}" : "Transferencia de variante {$variante->sku}", + 'usuario_id' => Auth::id() ?? 1, // Fallback a usuario administrador si no hay autenticación + 'fecha_transferencia' => now(), + ]); + + DB::commit(); + + return $transferencia; + + } catch (Exception $e) { + DB::rollBack(); + throw $e; + } + } + + /** + * Obtener el stock de una variante en una bodega específica + * + * @param ProductVariant $variante + * @param Bodega $bodega + * @return int + */ + private function obtenerStockVarianteEnBodega(ProductVariant $variante, Bodega $bodega): int + { + $relacion = $variante->bodegas()->where('bodega_id', $bodega->id)->first(); + return $relacion ? $relacion->pivot->stock : 0; + } + + /** + * Actualizar el stock de una variante en una bodega + * + * @param ProductVariant $variante + * @param Bodega $bodega + * @param int $nuevoStock + * @return void + */ + private function actualizarStockVarianteBodega(ProductVariant $variante, Bodega $bodega, int $nuevoStock): void + { + $existeRelacion = $variante->bodegas()->where('bodega_id', $bodega->id)->exists(); + + if ($existeRelacion) { + // Actualizar relación existente + $variante->bodegas()->updateExistingPivot($bodega->id, [ + 'stock' => $nuevoStock + ]); + } else { + // Crear nueva relación (solo si el stock es mayor a 0) + if ($nuevoStock > 0) { + $variante->bodegas()->attach($bodega->id, [ + 'stock' => $nuevoStock + ]); + } + } + } + + /** + * Obtener resumen de stock por bodega para una variante + * + * @param int $varianteId + * @return array + */ + public function obtenerResumenStockVariante(int $varianteId): array + { + $variante = ProductVariant::with(['bodegas', 'producto'])->findOrFail($varianteId); + + $resumen = [ + 'variante_id' => $varianteId, + 'variante_sku' => $variante->sku, + 'producto_nombre' => $variante->producto->nombre, + 'stock_total' => $variante->getStockEfectivo(), + 'bodegas' => [] + ]; + + if ($variante->bodegas()->exists()) { + foreach ($variante->bodegas as $bodega) { + $resumen['bodegas'][] = [ + 'bodega_id' => $bodega->id, + 'bodega_nombre' => $bodega->nombre, + 'stock' => $bodega->pivot->stock, + ]; + } + } else { + $resumen['stock_directo'] = $variante->stock; + } + + return $resumen; + } +} \ No newline at end of file diff --git a/artisan b/artisan new file mode 100644 index 0000000..c35e31d --- /dev/null +++ b/artisan @@ -0,0 +1,18 @@ +#!/usr/bin/env php +handleCommand(new ArgvInput); + +exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100644 index 0000000..d654276 --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,19 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + api: __DIR__.'/../routes/api.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware) { + // + }) + ->withExceptions(function (Exceptions $exceptions) { + // + })->create(); diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/bootstrap/providers.php b/bootstrap/providers.php new file mode 100644 index 0000000..22744d1 --- /dev/null +++ b/bootstrap/providers.php @@ -0,0 +1,6 @@ +=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, + { + "name": "danharrin/date-format-converter", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/danharrin/date-format-converter.git", + "reference": "7c31171bc981e48726729a5f3a05a2d2b63f0b1e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danharrin/date-format-converter/zipball/7c31171bc981e48726729a5f3a05a2d2b63f0b1e", + "reference": "7c31171bc981e48726729a5f3a05a2d2b63f0b1e", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/helpers.php", + "src/standards.php" + ], + "psr-4": { + "DanHarrin\\DateFormatConverter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dan Harrin", + "email": "dan@danharrin.com" + } + ], + "description": "Convert token-based date formats between standards.", + "homepage": "https://github.com/danharrin/date-format-converter", + "support": { + "issues": "https://github.com/danharrin/date-format-converter/issues", + "source": "https://github.com/danharrin/date-format-converter" + }, + "funding": [ + { + "url": "https://github.com/danharrin", + "type": "github" + } + ], + "time": "2024-06-13T09:38:44+00:00" + }, + { + "name": "danharrin/livewire-rate-limiting", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/danharrin/livewire-rate-limiting.git", + "reference": "14dde653a9ae8f38af07a0ba4921dc046235e1a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/danharrin/livewire-rate-limiting/zipball/14dde653a9ae8f38af07a0ba4921dc046235e1a0", + "reference": "14dde653a9ae8f38af07a0ba4921dc046235e1a0", + "shasum": "" + }, + "require": { + "illuminate/support": "^9.0|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "livewire/livewire": "^3.0", + "livewire/volt": "^1.3", + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "phpunit/phpunit": "^9.0|^10.0|^11.5.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "DanHarrin\\LivewireRateLimiting\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dan Harrin", + "email": "dan@danharrin.com" + } + ], + "description": "Apply rate limiters to Laravel Livewire actions.", + "homepage": "https://github.com/danharrin/livewire-rate-limiting", + "support": { + "issues": "https://github.com/danharrin/livewire-rate-limiting/issues", + "source": "https://github.com/danharrin/livewire-rate-limiting" + }, + "funding": [ + { + "url": "https://github.com/danharrin", + "type": "github" + } + ], + "time": "2025-02-21T08:52:11+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, + { + "name": "doctrine/dbal", + "version": "4.2.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "19a2b7deb5fe8c2df0ff817ecea305e50acb62ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/19a2b7deb5fe8c2df0ff817ecea305e50acb62ec", + "reference": "19a2b7deb5fe8c2df0ff817ecea305e50acb62ec", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3|^1", + "php": "^8.1", + "psr/cache": "^1|^2|^3", + "psr/log": "^1|^2|^3" + }, + "require-dev": { + "doctrine/coding-standard": "12.0.0", + "fig/log-test": "^1", + "jetbrains/phpstorm-stubs": "2023.2", + "phpstan/phpstan": "2.1.1", + "phpstan/phpstan-phpunit": "2.0.3", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "10.5.39", + "slevomat/coding-standard": "8.13.1", + "squizlabs/php_codesniffer": "3.10.2", + "symfony/cache": "^6.3.8|^7.0", + "symfony/console": "^5.4|^6.3|^7.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\DBAL\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", + "keywords": [ + "abstraction", + "database", + "db2", + "dbal", + "mariadb", + "mssql", + "mysql", + "oci8", + "oracle", + "pdo", + "pgsql", + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlite", + "sqlserver", + "sqlsrv" + ], + "support": { + "issues": "https://github.com/doctrine/dbal/issues", + "source": "https://github.com/doctrine/dbal/tree/4.2.2" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal", + "type": "tidelift" + } + ], + "time": "2025-01-16T08:40:56+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9", + "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12", + "phpstan/phpstan": "1.4.10 || 2.0.3", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psr/log": "^1 || ^2 || ^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.4" + }, + "time": "2024-12-07T21:18:45+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.0.10", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.10" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2024-02-18T20:23:39+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "8c784d071debd117328803d86b2097615b457500" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", + "reference": "8c784d071debd117328803d86b2097615b457500", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.0" + }, + "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" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2024-10-09T13:47:03+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.3", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "b115554301161fa21467629f1e1391c1936de517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/b115554301161fa21467629f1e1391c1936de517", + "reference": "b115554301161fa21467629f1e1391c1936de517", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.3" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2024-12-27T00:36:43+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.19.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0" + }, + "time": "2025-10-17T16:34:55+00:00" + }, + { + "name": "filament/actions", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/actions.git", + "reference": "acaaa861bc01f72a73cb5faedcc3fecbbbf599c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/actions/zipball/acaaa861bc01f72a73cb5faedcc3fecbbbf599c6", + "reference": "acaaa861bc01f72a73cb5faedcc3fecbbbf599c6", + "shasum": "" + }, + "require": { + "anourvalar/eloquent-serialize": "^1.2", + "filament/forms": "self.version", + "filament/infolists": "self.version", + "filament/notifications": "self.version", + "filament/support": "self.version", + "illuminate/contracts": "^10.45|^11.0|^12.0", + "illuminate/database": "^10.45|^11.0|^12.0", + "illuminate/support": "^10.45|^11.0|^12.0", + "league/csv": "^9.16", + "openspout/openspout": "^4.23", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\Actions\\ActionsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Filament\\Actions\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Easily add beautiful action modals to any Livewire component.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-02-25T08:19:06+00:00" + }, + { + "name": "filament/filament", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/panels.git", + "reference": "6ca7e497517a78413777ab74a0688a70337f6b4f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/panels/zipball/6ca7e497517a78413777ab74a0688a70337f6b4f", + "reference": "6ca7e497517a78413777ab74a0688a70337f6b4f", + "shasum": "" + }, + "require": { + "danharrin/livewire-rate-limiting": "^0.3|^1.0|^2.0", + "filament/actions": "self.version", + "filament/forms": "self.version", + "filament/infolists": "self.version", + "filament/notifications": "self.version", + "filament/support": "self.version", + "filament/tables": "self.version", + "filament/widgets": "self.version", + "illuminate/auth": "^10.45|^11.0|^12.0", + "illuminate/console": "^10.45|^11.0|^12.0", + "illuminate/contracts": "^10.45|^11.0|^12.0", + "illuminate/cookie": "^10.45|^11.0|^12.0", + "illuminate/database": "^10.45|^11.0|^12.0", + "illuminate/http": "^10.45|^11.0|^12.0", + "illuminate/routing": "^10.45|^11.0|^12.0", + "illuminate/session": "^10.45|^11.0|^12.0", + "illuminate/support": "^10.45|^11.0|^12.0", + "illuminate/view": "^10.45|^11.0|^12.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\FilamentServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/global_helpers.php", + "src/helpers.php" + ], + "psr-4": { + "Filament\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A collection of full-stack components for accelerated Laravel app development.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-03-05T09:26:29+00:00" + }, + { + "name": "filament/forms", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/forms.git", + "reference": "420f6b2b30288c853024d189213e38f644dd6f6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/forms/zipball/420f6b2b30288c853024d189213e38f644dd6f6e", + "reference": "420f6b2b30288c853024d189213e38f644dd6f6e", + "shasum": "" + }, + "require": { + "danharrin/date-format-converter": "^0.3", + "filament/actions": "self.version", + "filament/support": "self.version", + "illuminate/console": "^10.45|^11.0|^12.0", + "illuminate/contracts": "^10.45|^11.0|^12.0", + "illuminate/database": "^10.45|^11.0|^12.0", + "illuminate/filesystem": "^10.45|^11.0|^12.0", + "illuminate/support": "^10.45|^11.0|^12.0", + "illuminate/validation": "^10.45|^11.0|^12.0", + "illuminate/view": "^10.45|^11.0|^12.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\Forms\\FormsServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Filament\\Forms\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Easily add beautiful forms to any Livewire component.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-03-05T09:26:39+00:00" + }, + { + "name": "filament/infolists", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/infolists.git", + "reference": "3498bfd23670f94d9c2160d2a7382775dfc97430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/infolists/zipball/3498bfd23670f94d9c2160d2a7382775dfc97430", + "reference": "3498bfd23670f94d9c2160d2a7382775dfc97430", + "shasum": "" + }, + "require": { + "filament/actions": "self.version", + "filament/support": "self.version", + "illuminate/console": "^10.45|^11.0|^12.0", + "illuminate/contracts": "^10.45|^11.0|^12.0", + "illuminate/database": "^10.45|^11.0|^12.0", + "illuminate/filesystem": "^10.45|^11.0|^12.0", + "illuminate/support": "^10.45|^11.0|^12.0", + "illuminate/view": "^10.45|^11.0|^12.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\Infolists\\InfolistsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Filament\\Infolists\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Easily add beautiful read-only infolists to any Livewire component.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-03-03T08:11:43+00:00" + }, + { + "name": "filament/notifications", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/notifications.git", + "reference": "8cfe18e5d04ba72d777753ed632bbcf3408236a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/notifications/zipball/8cfe18e5d04ba72d777753ed632bbcf3408236a2", + "reference": "8cfe18e5d04ba72d777753ed632bbcf3408236a2", + "shasum": "" + }, + "require": { + "filament/actions": "self.version", + "filament/support": "self.version", + "illuminate/contracts": "^10.45|^11.0|^12.0", + "illuminate/filesystem": "^10.45|^11.0|^12.0", + "illuminate/notifications": "^10.45|^11.0|^12.0", + "illuminate/support": "^10.45|^11.0|^12.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\Notifications\\NotificationsServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/Testing/Autoload.php" + ], + "psr-4": { + "Filament\\Notifications\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Easily add beautiful notifications to any Livewire app.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-02-25T08:18:58+00:00" + }, + { + "name": "filament/support", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/support.git", + "reference": "fb5ff99b8f7559815434c109d505c12c141510da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/support/zipball/fb5ff99b8f7559815434c109d505c12c141510da", + "reference": "fb5ff99b8f7559815434c109d505c12c141510da", + "shasum": "" + }, + "require": { + "blade-ui-kit/blade-heroicons": "^2.5", + "doctrine/dbal": "^3.2|^4.0", + "ext-intl": "*", + "illuminate/contracts": "^10.45|^11.0|^12.0", + "illuminate/support": "^10.45|^11.0|^12.0", + "illuminate/view": "^10.45|^11.0|^12.0", + "kirschbaum-development/eloquent-power-joins": "^3.0|^4.0", + "livewire/livewire": "^3.5", + "php": "^8.1", + "ryangjchandler/blade-capture-directive": "^0.2|^0.3|^1.0", + "spatie/color": "^1.5", + "spatie/invade": "^1.0|^2.0", + "spatie/laravel-package-tools": "^1.9", + "symfony/console": "^6.0|^7.0", + "symfony/html-sanitizer": "^6.1|^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\Support\\SupportServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Filament\\Support\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Core helper methods and foundation code for all Filament packages.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-03-05T09:26:25+00:00" + }, + { + "name": "filament/tables", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/tables.git", + "reference": "5f2fbd8f0c6ffd19b2462269778ed96ce3c6fd35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/tables/zipball/5f2fbd8f0c6ffd19b2462269778ed96ce3c6fd35", + "reference": "5f2fbd8f0c6ffd19b2462269778ed96ce3c6fd35", + "shasum": "" + }, + "require": { + "filament/actions": "self.version", + "filament/forms": "self.version", + "filament/support": "self.version", + "illuminate/console": "^10.45|^11.0|^12.0", + "illuminate/contracts": "^10.45|^11.0|^12.0", + "illuminate/database": "^10.45|^11.0|^12.0", + "illuminate/filesystem": "^10.45|^11.0|^12.0", + "illuminate/support": "^10.45|^11.0|^12.0", + "illuminate/view": "^10.45|^11.0|^12.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\Tables\\TablesServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Filament\\Tables\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Easily add beautiful tables to any Livewire component.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-03-03T09:07:30+00:00" + }, + { + "name": "filament/widgets", + "version": "v3.3.3", + "source": { + "type": "git", + "url": "https://github.com/filamentphp/widgets.git", + "reference": "3bbd19044e19f93711f3690c441a3a0d35696aa1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filamentphp/widgets/zipball/3bbd19044e19f93711f3690c441a3a0d35696aa1", + "reference": "3bbd19044e19f93711f3690c441a3a0d35696aa1", + "shasum": "" + }, + "require": { + "filament/support": "self.version", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Filament\\Widgets\\WidgetsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Filament\\Widgets\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Easily add beautiful dashboard widgets to any Livewire component.", + "homepage": "https://github.com/filamentphp/filament", + "support": { + "issues": "https://github.com/filamentphp/filament/issues", + "source": "https://github.com/filamentphp/filament" + }, + "time": "2025-02-19T08:42:37+00:00" + }, + { + "name": "fruitcake/php-cors", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "symfony/http-foundation": "^4.4|^5.4|^6|^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barryvdh", + "email": "barryvdh@gmail.com" + } + ], + "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", + "homepage": "https://github.com/fruitcake/php-cors", + "keywords": [ + "cors", + "laravel", + "symfony" + ], + "support": { + "issues": "https://github.com/fruitcake/php-cors/issues", + "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2023-10-12T05:21:21+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2024-10-17T10:06:22+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "uri-template/tests": "1.0.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\UriTemplate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + } + ], + "description": "A polyfill class for uri_template of PHP", + "keywords": [ + "guzzlehttp", + "uri-template" + ], + "support": { + "issues": "https://github.com/guzzle/uri-template/issues", + "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/uri-template", + "type": "tidelift" + } + ], + "time": "2025-02-03T10:55:03+00:00" + }, + { + "name": "kirschbaum-development/eloquent-power-joins", + "version": "4.2.1", + "source": { + "type": "git", + "url": "https://github.com/kirschbaum-development/eloquent-power-joins.git", + "reference": "84a24784d9abde8bafb1998a0841a6bc10fa6f8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kirschbaum-development/eloquent-power-joins/zipball/84a24784d9abde8bafb1998a0841a6bc10fa6f8e", + "reference": "84a24784d9abde8bafb1998a0841a6bc10fa6f8e", + "shasum": "" + }, + "require": { + "illuminate/database": "^11.42|^12.0", + "illuminate/support": "^11.42|^12.0", + "php": "^8.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "dev-master", + "laravel/legacy-factories": "^1.0@dev", + "orchestra/testbench": "^9.0|^10.0", + "phpunit/phpunit": "^10.0|^11.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Kirschbaum\\PowerJoins\\PowerJoinsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Kirschbaum\\PowerJoins\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luis Dalmolin", + "email": "luis.nh@gmail.com", + "role": "Developer" + } + ], + "description": "The Laravel magic applied to joins.", + "homepage": "https://github.com/kirschbaum-development/eloquent-power-joins", + "keywords": [ + "eloquent", + "join", + "laravel", + "mysql" + ], + "support": { + "issues": "https://github.com/kirschbaum-development/eloquent-power-joins/issues", + "source": "https://github.com/kirschbaum-development/eloquent-power-joins/tree/4.2.1" + }, + "time": "2025-03-05T10:11:33+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.1.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "9be5738f1ca1530055bb9d6db81f909a7ed34842" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/9be5738f1ca1530055bb9d6db81f909a7ed34842", + "reference": "9be5738f1ca1530055bb9d6db81f909a7ed34842", + "shasum": "" + }, + "require": { + "brick/math": "^0.11|^0.12", + "composer-runtime-api": "^2.2", + "doctrine/inflector": "^2.0.5", + "dragonmantank/cron-expression": "^3.4", + "egulias/email-validator": "^3.2.1|^4.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-session": "*", + "ext-tokenizer": "*", + "fruitcake/php-cors": "^1.3", + "guzzlehttp/guzzle": "^7.8.2", + "guzzlehttp/uri-template": "^1.0", + "laravel/prompts": "^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "league/commonmark": "^2.6", + "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", + "php": "^8.2", + "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", + "symfony/polyfill-php83": "^1.31", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.5", + "vlucas/phpdotenv": "^5.6.1", + "voku/portable-ascii": "^2.0.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "psr/log-implementation": "1.0|2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/collections": "self.version", + "illuminate/concurrency": "self.version", + "illuminate/conditionable": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/macroable": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/process": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/testing": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "spatie/once": "*" + }, + "require-dev": { + "ably/ably-php": "^1.0", + "aws/aws-sdk-php": "^3.322.9", + "ext-gmp": "*", + "fakerphp/faker": "^1.24", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", + "league/flysystem-aws-s3-v3": "^3.25.1", + "league/flysystem-ftp": "^3.25.1", + "league/flysystem-path-prefixing": "^3.25.1", + "league/flysystem-read-only": "^3.25.1", + "league/flysystem-sftp-v3": "^3.25.1", + "mockery/mockery": "^1.6.10", + "orchestra/testbench-core": "^10.0.0", + "pda/pheanstalk": "^5.0.6", + "php-http/discovery": "^1.15", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3", + "resend/resend-php": "^0.10.0", + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" + }, + "suggest": { + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", + "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", + "ext-apcu": "Required to use the APC cache driver.", + "ext-fileinfo": "Required to use the Filesystem class.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", + "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.", + "ext-pdo": "Required to use all database features.", + "ext-posix": "Required to use all features of the queue worker.", + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", + "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).", + "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", + "mockery/mockery": "Required to use mocking (^1.6).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", + "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).", + "predis/predis": "Required to use the predis connector (^2.3).", + "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).", + "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).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Collections/functions.php", + "src/Illuminate/Collections/helpers.php", + "src/Illuminate/Events/functions.php", + "src/Illuminate/Filesystem/functions.php", + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Log/functions.php", + "src/Illuminate/Support/functions.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/", + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-03-05T15:31:19+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.3.5", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/console": "^6.2|^7.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", + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3|^3.4", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-mockery": "^1.1" + }, + "suggest": { + "ext-pcntl": "Required for the spinner to be animated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.3.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Laravel\\Prompts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "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.5" + }, + "time": "2025-02-11T13:34:40+00:00" + }, + { + "name": "laravel/sanctum", + "version": "v4.0.8", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/ec1dd9ddb2ab370f79dfe724a101856e0963f43c", + "reference": "ec1dd9ddb2ab370f79dfe724a101856e0963f43c", + "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", + "php": "^8.2", + "symfony/console": "^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "orchestra/testbench": "^9.0|^10.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2025-01-26T19:34:36+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "f379c13663245f7aa4512a7869f62eb14095f23f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f379c13663245f7aa4512a7869f62eb14095f23f", + "reference": "f379c13663245f7aa4512a7869f62eb14095f23f", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2025-02-11T15:03:05+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.10.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "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" + }, + "require-dev": { + "mockery/mockery": "~1.3.3|^1.4.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "support": { + "issues": "https://github.com/laravel/tinker/issues", + "source": "https://github.com/laravel/tinker/tree/v2.10.1" + }, + "time": "2025-01-27T14:24:01+00:00" + }, + { + "name": "league/commonmark", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/d990688c91cedfb69753ffc2512727ec646df2ad", + "reference": "d990688c91cedfb69753ffc2512727ec646df2ad", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "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", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2024-12-29T14:10:59+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "league/csv", + "version": "9.22.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/csv.git", + "reference": "afc109aa11f3086b8be8dfffa04ac31480b36b76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/afc109aa11f3086b8be8dfffa04ac31480b36b76", + "reference": "afc109aa11f3086b8be8dfffa04ac31480b36b76", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1.2" + }, + "require-dev": { + "ext-dom": "*", + "ext-xdebug": "*", + "friendsofphp/php-cs-fixer": "^3.69.0", + "phpbench/phpbench": "^1.4.0", + "phpstan/phpstan": "^1.12.18", + "phpstan/phpstan-deprecation-rules": "^1.2.1", + "phpstan/phpstan-phpunit": "^1.4.2", + "phpstan/phpstan-strict-rules": "^1.6.2", + "phpunit/phpunit": "^10.5.16 || ^11.5.7", + "symfony/var-dumper": "^6.4.8 || ^7.2.3" + }, + "suggest": { + "ext-dom": "Required to use the XMLConverter and the HTMLConverter classes", + "ext-iconv": "Needed to ease transcoding CSV using iconv stream filters", + "ext-mbstring": "Needed to ease transcoding CSV using mb stream filters", + "ext-mysqli": "Requiered to use the package with the MySQLi extension", + "ext-pdo": "Required to use the package with the PDO extension", + "ext-pgsql": "Requiered to use the package with the PgSQL extension", + "ext-sqlite3": "Required to use the package with the SQLite3 extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "League\\Csv\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://github.com/nyamsprod/", + "role": "Developer" + } + ], + "description": "CSV data manipulation made easy in PHP", + "homepage": "https://csv.thephpleague.com", + "keywords": [ + "convert", + "csv", + "export", + "filter", + "import", + "read", + "transform", + "write" + ], + "support": { + "docs": "https://csv.thephpleague.com", + "issues": "https://github.com/thephpleague/csv/issues", + "rss": "https://github.com/thephpleague/csv/releases.atom", + "source": "https://github.com/thephpleague/csv" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2025-02-28T10:00:39+00:00" + }, + { + "name": "league/flysystem", + "version": "3.29.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319", + "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.29.1" + }, + "time": "2024-10-08T08:58:34+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.29.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0" + }, + "time": "2024-08-09T21:24:39+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-09-21T08:32:55+00:00" + }, + { + "name": "league/uri", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "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", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "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" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "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" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:18:47+00:00" + }, + { + "name": "livewire/livewire", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/livewire/livewire.git", + "reference": "0df0a762698176d714e42e2dfed92b6b9e24b8e4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/livewire/livewire/zipball/0df0a762698176d714e42e2dfed92b6b9e24b8e4", + "reference": "0df0a762698176d714e42e2dfed92b6b9e24b8e4", + "shasum": "" + }, + "require": { + "illuminate/database": "^10.0|^11.0|^12.0", + "illuminate/routing": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/validation": "^10.0|^11.0|^12.0", + "laravel/prompts": "^0.1.24|^0.2|^0.3", + "league/mime-type-detection": "^1.9", + "php": "^8.1", + "symfony/console": "^6.0|^7.0", + "symfony/http-kernel": "^6.2|^7.0" + }, + "require-dev": { + "calebporzio/sushi": "^2.1", + "laravel/framework": "^10.15.0|^11.0|^12.0", + "mockery/mockery": "^1.3.1", + "orchestra/testbench": "^8.21.0|^9.0|^10.0", + "orchestra/testbench-dusk": "^8.24|^9.1|^10.0", + "phpunit/phpunit": "^10.4|^11.5", + "psy/psysh": "^0.11.22|^0.12" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Livewire": "Livewire\\Livewire" + }, + "providers": [ + "Livewire\\LivewireServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Livewire\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Caleb Porzio", + "email": "calebporzio@gmail.com" + } + ], + "description": "A front-end framework for Laravel.", + "support": { + "issues": "https://github.com/livewire/livewire/issues", + "source": "https://github.com/livewire/livewire/tree/v3.6.1" + }, + "funding": [ + { + "url": "https://github.com/livewire", + "type": "github" + } + ], + "time": "2025-03-04T21:48:52+00:00" + }, + { + "name": "maatwebsite/excel", + "version": "3.1.67", + "source": { + "type": "git", + "url": "https://github.com/SpartnerNL/Laravel-Excel.git", + "reference": "e508e34a502a3acc3329b464dad257378a7edb4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/e508e34a502a3acc3329b464dad257378a7edb4d", + "reference": "e508e34a502a3acc3329b464dad257378a7edb4d", + "shasum": "" + }, + "require": { + "composer/semver": "^3.3", + "ext-json": "*", + "illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0", + "php": "^7.0||^8.0", + "phpoffice/phpspreadsheet": "^1.30.0", + "psr/simple-cache": "^1.0||^2.0||^3.0" + }, + "require-dev": { + "laravel/scout": "^7.0||^8.0||^9.0||^10.0", + "orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0", + "predis/predis": "^1.1" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Excel": "Maatwebsite\\Excel\\Facades\\Excel" + }, + "providers": [ + "Maatwebsite\\Excel\\ExcelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Maatwebsite\\Excel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Patrick Brouwers", + "email": "patrick@spartner.nl" + } + ], + "description": "Supercharged Excel exports and imports in Laravel", + "keywords": [ + "PHPExcel", + "batch", + "csv", + "excel", + "export", + "import", + "laravel", + "php", + "phpspreadsheet" + ], + "support": { + "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.67" + }, + "funding": [ + { + "url": "https://laravel-excel.com/commercial-support", + "type": "custom" + }, + { + "url": "https://github.com/patrickbrouwers", + "type": "github" + } + ], + "time": "2025-08-26T09:13:16+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "3.1.2", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f", + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.2" + }, + "require-dev": { + "brianium/paratest": "^7.7", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.16", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^11.0", + "vimeo/psalm": "^6.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + } + ], + "time": "2025-01-27T12:07:53+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, + { + "name": "masterminds/html5", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + }, + "time": "2024-03-31T07:05:07+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.8.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "reference": "aef6ee73a77a66e404dd6540934a9ef1b3c855b4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.8.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2024-12-05T17:15:07+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.8.6", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/ff2f20cf83bd4d503720632ce8a426dc747bf7fd", + "reference": "ff2f20cf83bd4d503720632ce8a426dc747bf7fd", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3 || ^7.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1|| ^6.0 || ^7.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.57.2", + "kylekatarnls/multi-tester": "^2.5.3", + "ondrejmirtes/better-reflection": "^6.25.0.4", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.11.2", + "phpunit/phpunit": "^10.5.20", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2025-02-20T17:33:38+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.5.2", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.2" + }, + "time": "2024-10-06T23:10:23+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.5", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", + "shasum": "" + }, + "require": { + "php": "8.0 - 8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.5" + }, + "time": "2024-08-07T15:39:19+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/52915afe6a1044e8b9cee1bcff836fb63acf9cda", + "reference": "52915afe6a1044e8b9cee1bcff836fb63acf9cda", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.1.8" + }, + "require-dev": { + "illuminate/console": "^11.33.2", + "laravel/pint": "^1.18.2", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0", + "phpstan/phpstan": "^1.12.11", + "phpstan/phpstan-strict-rules": "^1.6.1", + "symfony/var-dumper": "^7.1.8", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Its like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2024-11-21T10:39:51+00:00" + }, + { + "name": "openspout/openspout", + "version": "v4.28.5", + "source": { + "type": "git", + "url": "https://github.com/openspout/openspout.git", + "reference": "ab05a09fe6fce57c90338f83280648a9786ce36b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/openspout/openspout/zipball/ab05a09fe6fce57c90338f83280648a9786ce36b", + "reference": "ab05a09fe6fce57c90338f83280648a9786ce36b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-filter": "*", + "ext-libxml": "*", + "ext-xmlreader": "*", + "ext-zip": "*", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "ext-zlib": "*", + "friendsofphp/php-cs-fixer": "^3.68.3", + "infection/infection": "^0.29.10", + "phpbench/phpbench": "^1.4.0", + "phpstan/phpstan": "^2.1.2", + "phpstan/phpstan-phpunit": "^2.0.4", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^11.5.4" + }, + "suggest": { + "ext-iconv": "To handle non UTF-8 CSV files (if \"php-mbstring\" is not already installed or is too limited)", + "ext-mbstring": "To handle non UTF-8 CSV files (if \"iconv\" is not already installed)" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3.x-dev" + } + }, + "autoload": { + "psr-4": { + "OpenSpout\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Adrien Loison", + "email": "adrien@box.com" + } + ], + "description": "PHP Library to read and write spreadsheet files (CSV, XLSX and ODS), in a fast and scalable way", + "homepage": "https://github.com/openspout/openspout", + "keywords": [ + "OOXML", + "csv", + "excel", + "memory", + "odf", + "ods", + "office", + "open", + "php", + "read", + "scale", + "spreadsheet", + "stream", + "write", + "xlsx" + ], + "support": { + "issues": "https://github.com/openspout/openspout/issues", + "source": "https://github.com/openspout/openspout/tree/v4.28.5" + }, + "funding": [ + { + "url": "https://paypal.me/filippotessarotto", + "type": "custom" + }, + { + "url": "https://github.com/Slamdunk", + "type": "github" + } + ], + "time": "2025-01-30T13:51:11+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.30.1", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "fa8257a579ec623473eabfe49731de5967306c4c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fa8257a579ec623473eabfe49731de5967306c4c", + "reference": "fa8257a579ec623473eabfe49731de5967306c4c", + "shasum": "" + }, + "require": { + "composer/pcre": "^1||^2||^3", + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": ">=7.4.0 <8.5.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^1.0 || ^2.0 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.30.1" + }, + "time": "2025-10-26T16:01:04+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:41:07+00:00" + }, + { + "name": "picqer/php-barcode-generator", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/picqer/php-barcode-generator.git", + "reference": "3ef0b26ebd3996e8bb9e90fa2059a67d2e482b3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/picqer/php-barcode-generator/zipball/3ef0b26ebd3996e8bb9e90fa2059a67d2e482b3e", + "reference": "3ef0b26ebd3996e8bb9e90fa2059a67d2e482b3e", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "ext-bcmath": "Barcode IMB (Intelligent Mail Barcode) needs bcmath extension", + "ext-gd": "For JPG and PNG generators, GD or Imagick is required", + "ext-imagick": "For JPG and PNG generators, GD or Imagick is required" + }, + "type": "library", + "autoload": { + "psr-4": { + "Picqer\\Barcode\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Casper Bakker", + "email": "info@picqer.com", + "homepage": "https://picqer.com" + }, + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "homepage": "http://nicolaasuni.tecnick.com" + } + ], + "description": "An easy to use, non-bloated, barcode generator in PHP. Creates SVG, PNG, JPG and HTML images from the most used 1D barcode standards.", + "homepage": "https://github.com/picqer/php-barcode-generator", + "keywords": [ + "CODABAR", + "Code11", + "Code93", + "EAN13", + "KIX", + "KIXCODE", + "MSI", + "POSTNET", + "Pharma", + "Standard 2 of 5", + "barcode", + "barcode generator", + "code128", + "code39", + "ean", + "html", + "jpeg", + "jpg", + "php", + "png", + "svg", + "upc" + ], + "support": { + "issues": "https://github.com/picqer/php-barcode-generator/issues", + "source": "https://github.com/picqer/php-barcode-generator/tree/v3.2.0" + }, + "time": "2024-10-01T19:35:25+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.12.8", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625", + "shasum": "" + }, + "require": { + "ext-json": "*", + "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" + }, + "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" + }, + "suggest": { + "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": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": false, + "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.8" + }, + "time": "2025-03-16T03:05:19+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/collection", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109", + "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.1.0" + }, + "time": "2025-03-02T04:48:29+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.7.6", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", + "ext-json": "*", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.8", + "ergebnis/composer-normalize": "^2.15", + "mockery/mockery": "^1.3", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", + "php-mock/php-mock-mockery": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^8.5 || ^9", + "ramsey/composer-repl": "^1.4", + "slevomat/coding-standard": "^8.4", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.7.6" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "time": "2024-04-27T21:32:50+00:00" + }, + { + "name": "ryangjchandler/blade-capture-directive", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/ryangjchandler/blade-capture-directive.git", + "reference": "bbb1513dfd89eaec87a47fe0c449a7e3d4a1976d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ryangjchandler/blade-capture-directive/zipball/bbb1513dfd89eaec87a47fe0c449a7e3d4a1976d", + "reference": "bbb1513dfd89eaec87a47fe0c449a7e3d4a1976d", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.0|^11.0|^12.0", + "php": "^8.1", + "spatie/laravel-package-tools": "^1.9.2" + }, + "require-dev": { + "nunomaduro/collision": "^7.0|^8.0", + "nunomaduro/larastan": "^2.0|^3.0", + "orchestra/testbench": "^8.0|^9.0|^10.0", + "pestphp/pest": "^2.0|^3.7", + "pestphp/pest-plugin-laravel": "^2.0|^3.1", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan-deprecation-rules": "^1.0|^2.0", + "phpstan/phpstan-phpunit": "^1.0|^2.0", + "phpunit/phpunit": "^10.0|^11.5.3", + "spatie/laravel-ray": "^1.26" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "BladeCaptureDirective": "RyanChandler\\BladeCaptureDirective\\Facades\\BladeCaptureDirective" + }, + "providers": [ + "RyanChandler\\BladeCaptureDirective\\BladeCaptureDirectiveServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "RyanChandler\\BladeCaptureDirective\\": "src", + "RyanChandler\\BladeCaptureDirective\\Database\\Factories\\": "database/factories" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ryan Chandler", + "email": "support@ryangjchandler.co.uk", + "role": "Developer" + } + ], + "description": "Create inline partials in your Blade templates with ease.", + "homepage": "https://github.com/ryangjchandler/blade-capture-directive", + "keywords": [ + "blade-capture-directive", + "laravel", + "ryangjchandler" + ], + "support": { + "issues": "https://github.com/ryangjchandler/blade-capture-directive/issues", + "source": "https://github.com/ryangjchandler/blade-capture-directive/tree/v1.1.0" + }, + "funding": [ + { + "url": "https://github.com/ryangjchandler", + "type": "github" + } + ], + "time": "2025-02-25T09:09:36+00:00" + }, + { + "name": "spatie/color", + "version": "1.8.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/color.git", + "reference": "142af7fec069a420babea80a5412eb2f646dcd8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/color/zipball/142af7fec069a420babea80a5412eb2f646dcd8c", + "reference": "142af7fec069a420babea80a5412eb2f646dcd8c", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.22", + "phpunit/phpunit": "^6.5||^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\Color\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sebastian De Deyne", + "email": "sebastian@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A little library to handle color conversions", + "homepage": "https://github.com/spatie/color", + "keywords": [ + "color", + "conversion", + "rgb", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/color/issues", + "source": "https://github.com/spatie/color/tree/1.8.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-02-10T09:22:41+00:00" + }, + { + "name": "spatie/invade", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/invade.git", + "reference": "b920f6411d21df4e8610a138e2e87ae4957d7f63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/invade/zipball/b920f6411d21df4e8610a138e2e87ae4957d7f63", + "reference": "b920f6411d21df4e8610a138e2e87ae4957d7f63", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.20", + "phpstan/phpstan": "^1.4", + "spatie/ray": "^1.28" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Spatie\\Invade\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "A PHP function to work with private properties and methods", + "homepage": "https://github.com/spatie/invade", + "keywords": [ + "invade", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/invade/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2024-05-17T09:06:10+00:00" + }, + { + "name": "spatie/laravel-package-tools", + "version": "1.19.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa", + "reference": "1c9c30ac6a6576b8d15c6c37b6cf23d748df2faa", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.28|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^7.7|^8.0|^9.0|^10.0", + "pestphp/pest": "^1.23|^2.1|^3.1", + "phpunit/phpunit": "^9.5.24|^10.5|^11.5", + "spatie/pest-plugin-test-time": "^1.1|^2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.19.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-02-06T14:58:20+00:00" + }, + { + "name": "spatie/laravel-permission", + "version": "6.16.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-permission.git", + "reference": "4fa03c06509e037a4d42c131d0f181e3e4bbd483" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/4fa03c06509e037a4d42c131d0f181e3e4bbd483", + "reference": "4fa03c06509e037a4d42c131d0f181e3e4bbd483", + "shasum": "" + }, + "require": { + "illuminate/auth": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/container": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/database": "^8.12|^9.0|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "laravel/passport": "^11.0|^12.0", + "laravel/pint": "^1.0", + "orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0", + "phpunit/phpunit": "^9.4|^10.1|^11.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\Permission\\PermissionServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "6.x-dev", + "dev-master": "6.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Permission\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Permission handling for Laravel 8.0 and up", + "homepage": "https://github.com/spatie/laravel-permission", + "keywords": [ + "acl", + "laravel", + "permission", + "permissions", + "rbac", + "roles", + "security", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-permission/issues", + "source": "https://github.com/spatie/laravel-permission/tree/6.16.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2025-02-28T20:29:57+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/console", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/0e2e3f38c192e93e622e41ec37f4ca70cfedf218", + "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-07T19:09:28+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/aabf79938aa795350c07ce6464dd1985607d95d5", + "reference": "aabf79938aa795350c07ce6464dd1985607d95d5", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-02T20:27:07+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "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/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:17+00:00" + }, + { + "name": "symfony/html-sanitizer", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/html-sanitizer.git", + "reference": "91443febe34cfa5e8e00425f892e6316db95bc23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/91443febe34cfa5e8e00425f892e6316db95bc23", + "reference": "91443febe34cfa5e8e00425f892e6316db95bc23", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "league/uri": "^6.5|^7.0", + "masterminds/html5": "^2.7.2", + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HtmlSanitizer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Titouan Galopin", + "email": "galopintitouan@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to sanitize untrusted HTML input for safe insertion into a document's DOM.", + "homepage": "https://symfony.com", + "keywords": [ + "Purifier", + "html", + "sanitizer" + ], + "support": { + "source": "https://github.com/symfony/html-sanitizer/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-27T11:08:17+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ee1b504b8926198be89d05e5b6fc4c3810c090f0", + "reference": "ee1b504b8926198be89d05e5b6fc4c3810c090f0", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5", + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T10:56:55+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "9f1103734c5789798fefb90e91de4586039003ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f1103734c5789798fefb90e91de4586039003ed", + "reference": "9f1103734c5789798fefb90e91de4586039003ed", + "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": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "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/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/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", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "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.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-26T11:01:22+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f3871b182c44997cf039f3b462af4a48fb85f9d3", + "reference": "f3871b182c44997cf039f3b462af4a48fb85f9d3", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/mime": "^7.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-27T11:08:17+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/87ca22046b78c3feaff04b337f33b38510fd686b", + "reference": "87ca22046b78c3feaff04b337f33b38510fd686b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "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", + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-19T08:51:20+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773", + "reference": "c36586dcf89a12315939e00ec9b4474adcb1d773", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-05T08:33:46+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/ee9a67edc6baa33e5fae662f94f91fd262930996", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "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" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T10:56:55+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/a214fe7d62bd4df2a76447c67c6b26e1d5e74931", + "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "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/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-20T20:18:16+00:00" + }, + { + "name": "symfony/translation", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/283856e6981286cc0d800b53bd5703e8e363f05a", + "reference": "283856e6981286cc0d800b53bd5703e8e363f05a", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^4.18|^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/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-13T10:27:23+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/2d294d0c48df244c71c105a169d0190bfb080426", + "reference": "2d294d0c48df244c71c105a169d0190bfb080426", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "9c46038cd4ed68952166cf7001b54eb539184ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9c46038cd4ed68952166cf7001b54eb539184ccb", + "reference": "9c46038cd4ed68952166cf7001b54eb539184ccb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "ext-iconv": "*", + "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", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-09T08:14:01+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + }, + "time": "2024-12-21T16:25:41+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "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" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:52:34+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "https://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2024-11-21T01:49:47+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": [ + { + "name": "archtechx/enums", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/archtechx/enums.git", + "reference": "27d0405b983b14a2ee90621c4034eeb6010c0a0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/archtechx/enums/zipball/27d0405b983b14a2ee90621c4034eeb6010c0a0c", + "reference": "27d0405b983b14a2ee90621c4034eeb6010c0a0c", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "larastan/larastan": "^2.4", + "orchestra/testbench": "^8.0", + "pestphp/pest": "^2.0", + "pestphp/pest-plugin-laravel": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ArchTech\\Enums\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Samuel Štancl", + "email": "samuel@archte.ch" + } + ], + "description": "Helpers for making PHP enums more lovable.", + "support": { + "issues": "https://github.com/archtechx/enums/issues", + "source": "https://github.com/archtechx/enums/tree/v1.1.1" + }, + "time": "2024-10-29T15:38:32+00:00" + }, + { + "name": "dragon-code/contracts", + "version": "2.24.0", + "source": { + "type": "git", + "url": "https://github.com/TheDragonCode/contracts.git", + "reference": "c21ea4fc0a399bd803a2805a7f2c989749083896" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TheDragonCode/contracts/zipball/c21ea4fc0a399bd803a2805a7f2c989749083896", + "reference": "c21ea4fc0a399bd803a2805a7f2c989749083896", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-message": "^1.0.1 || ^2.0", + "symfony/http-kernel": "^4.0 || ^5.0 || ^6.0 || ^7.0", + "symfony/polyfill-php80": "^1.23" + }, + "conflict": { + "andrey-helldar/contracts": "*" + }, + "require-dev": { + "illuminate/database": "^10.0 || ^11.0 || ^12.0", + "phpdocumentor/reflection-docblock": "^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "DragonCode\\Contracts\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + } + ], + "description": "A set of contracts for any project", + "keywords": [ + "contracts", + "interfaces" + ], + "support": { + "source": "https://github.com/TheDragonCode/contracts" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2025-02-23T23:11:50+00:00" + }, + { + "name": "dragon-code/pretty-array", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/TheDragonCode/pretty-array.git", + "reference": "b94034d92172a5d14a578822d68b2a8f8b5388e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TheDragonCode/pretty-array/zipball/b94034d92172a5d14a578822d68b2a8f8b5388e0", + "reference": "b94034d92172a5d14a578822d68b2a8f8b5388e0", + "shasum": "" + }, + "require": { + "dragon-code/contracts": "^2.20", + "dragon-code/support": "^6.11.2", + "ext-dom": "*", + "ext-mbstring": "*", + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^10.0 || ^11.0 || ^12.0" + }, + "suggest": { + "symfony/thanks": "Give thanks (in the form of a GitHub) to your fellow PHP package maintainers" + }, + "type": "library", + "autoload": { + "psr-4": { + "DragonCode\\PrettyArray\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + } + ], + "description": "Simple conversion of an array to a pretty view", + "keywords": [ + "andrey helldar", + "array", + "dragon", + "dragon code", + "pretty", + "pretty array" + ], + "support": { + "issues": "https://github.com/TheDragonCode/pretty-array/issues", + "source": "https://github.com/TheDragonCode/pretty-array" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2025-02-24T15:35:24+00:00" + }, + { + "name": "dragon-code/support", + "version": "6.16.0", + "source": { + "type": "git", + "url": "https://github.com/TheDragonCode/support.git", + "reference": "ab9b657a307e75f6ba5b2b39e1e45207dc1a065a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TheDragonCode/support/zipball/ab9b657a307e75f6ba5b2b39e1e45207dc1a065a", + "reference": "ab9b657a307e75f6ba5b2b39e1e45207dc1a065a", + "shasum": "" + }, + "require": { + "dragon-code/contracts": "^2.22.0", + "ext-bcmath": "*", + "ext-ctype": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": "^8.1", + "psr/http-message": "^1.0.1 || ^2.0", + "symfony/polyfill-php81": "^1.25", + "voku/portable-ascii": "^1.4.8 || ^2.0.1" + }, + "conflict": { + "andrey-helldar/support": "*" + }, + "require-dev": { + "illuminate/contracts": "^9.0 || ^10.0 || ^11.0 || ^12.0", + "phpunit/phpunit": "^9.6 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "suggest": { + "dragon-code/laravel-support": "Various helper files for the Laravel and Lumen frameworks", + "symfony/thanks": "Give thanks (in the form of a GitHub) to your fellow PHP package maintainers" + }, + "type": "library", + "extra": { + "dragon-code": { + "docs-generator": { + "preview": { + "brand": "php", + "vendor": "The Dragon Code" + } + } + } + }, + "autoload": { + "psr-4": { + "DragonCode\\Support\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + } + ], + "description": "Support package is a collection of helpers and tools for any project.", + "keywords": [ + "dragon", + "dragon-code", + "framework", + "helper", + "helpers", + "laravel", + "php", + "support", + "symfony", + "yii", + "yii2" + ], + "support": { + "issues": "https://github.com/TheDragonCode/support/issues", + "source": "https://github.com/TheDragonCode/support" + }, + "funding": [ + { + "url": "https://boosty.to/dragon-code", + "type": "boosty" + }, + { + "url": "https://yoomoney.ru/to/410012608840929", + "type": "yoomoney" + } + ], + "time": "2025-02-24T14:01:52+00:00" + }, + { + "name": "fakerphp/faker", + "version": "v1.24.1", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1" + }, + "time": "2024-11-21T13:46:39+00:00" + }, + { + "name": "filp/whoops", + "version": "2.17.0", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "075bc0c26631110584175de6523ab3f1652eb28e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/075bc0c26631110584175de6523ab3f1652eb28e", + "reference": "075bc0c26631110584175de6523ab3f1652eb28e", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.17.0" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-01-25T12:00:00+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1" + }, + "time": "2020-07-09T08:09:16+00:00" + }, + { + "name": "laravel-lang/config", + "version": "1.12.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/config.git", + "reference": "b0dcfe44e76afe2e5049405195cf6fb3bb43a1fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/config/zipball/b0dcfe44e76afe2e5049405195cf6fb3bb43a1fb", + "reference": "b0dcfe44e76afe2e5049405195cf6fb3bb43a1fb", + "shasum": "" + }, + "require": { + "archtechx/enums": "^1.0", + "illuminate/config": "^10.0 || ^11.0 || ^12.0", + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.5", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^8.23 || ^9.1 || ^10.0", + "pestphp/pest": "^2.34 || ^3.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Config\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Config\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The Laravel-Lang config package", + "keywords": [ + "Laravel-lang", + "Settings", + "config", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "localizations", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/config/issues", + "source": "https://github.com/Laravel-Lang/config/tree/1.12.0" + }, + "time": "2025-02-24T20:10:37+00:00" + }, + { + "name": "laravel-lang/lang", + "version": "15.19.4", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/lang.git", + "reference": "47f466b3c592dffae3db18e9dc608a5b690f6ea4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/lang/zipball/47f466b3c592dffae3db18e9dc608a5b690f6ea4", + "reference": "47f466b3c592dffae3db18e9dc608a5b690f6ea4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel-lang/publisher": "^16.0", + "php": "^8.2" + }, + "conflict": { + "laravel/framework": "<11.0.7" + }, + "require-dev": { + "laravel-lang/status-generator": "^2.11", + "phpunit/phpunit": "^10.0 || ^11.0 || ^12.0", + "symfony/var-dumper": "^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Lang\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Lang\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laravel-Lang Team", + "homepage": "https://github.com/Laravel-Lang" + } + ], + "description": "List of 126 languages for Laravel Framework, Laravel Jetstream, Laravel Fortify, Laravel Breeze, Laravel Cashier, Laravel Nova, Laravel Spark and Laravel UI", + "keywords": [ + "lang", + "languages", + "laravel", + "lpm" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/lang/issues", + "source": "https://github.com/Laravel-Lang/lang" + }, + "time": "2025-03-05T13:41:45+00:00" + }, + { + "name": "laravel-lang/locale-list", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/locale-list.git", + "reference": "a214a3d49b1bcd1d5111cc1bb9653f0280f223d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/locale-list/zipball/a214a3d49b1bcd1d5111cc1bb9653f0280f223d3", + "reference": "a214a3d49b1bcd1d5111cc1bb9653f0280f223d3", + "shasum": "" + }, + "require": { + "archtechx/enums": "^0.3.2 || ^1.0", + "php": "^8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\LocaleList\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro", + "homepage": "https://dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "List of localizations available in Laravel Lang projects", + "keywords": [ + "Laravel-lang", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/locale-list/issues", + "source": "https://github.com/Laravel-Lang/locale-list" + }, + "time": "2025-02-24T19:11:00+00:00" + }, + { + "name": "laravel-lang/locales", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/locales.git", + "reference": "8c1d2383ced70a919b3c2f430589be6c81663087" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/locales/zipball/8c1d2383ced70a919b3c2f430589be6c81663087", + "reference": "8c1d2383ced70a919b3c2f430589be6c81663087", + "shasum": "" + }, + "require": { + "archtechx/enums": "^0.3.2 || ^1.0", + "dragon-code/support": "^6.11.3", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/config": "^1.12", + "laravel-lang/locale-list": "^1.5", + "laravel-lang/native-country-names": "^1.5", + "laravel-lang/native-currency-names": "^1.6", + "laravel-lang/native-locale-names": "^2.5", + "php": "^8.1" + }, + "require-dev": { + "orchestra/testbench": "^8.0 || ^9.0 || ^10.0", + "pestphp/pest": "^2.24.1 || ^3.0", + "symfony/var-dumper": "^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Locales\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Locales\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "Basic functionality for working with localizations", + "keywords": [ + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/locales/issues", + "source": "https://github.com/Laravel-Lang/locales" + }, + "time": "2025-02-24T20:38:10+00:00" + }, + { + "name": "laravel-lang/native-country-names", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/native-country-names.git", + "reference": "bb88d4bc54c309cb52d1de04bbdc0b2db651247c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/native-country-names/zipball/bb88d4bc54c309cb52d1de04bbdc0b2db651247c", + "reference": "bb88d4bc54c309cb52d1de04bbdc0b2db651247c", + "shasum": "" + }, + "require": { + "dragon-code/support": "^6.11", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.5", + "pestphp/pest": "^2.24.3 || ^3.0", + "punic/punic": "^3.8", + "symfony/console": "^6.3 || ^7.0", + "symfony/process": "^6.3 || ^7.0", + "symfony/var-dumper": "^6.3 || ^7.0", + "vlucas/phpdotenv": "^5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\NativeCountryNames\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The project contains native translations of country names", + "keywords": [ + "Laravel-lang", + "countries", + "country", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "territories", + "territory", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/native-country-names/issues", + "source": "https://github.com/Laravel-Lang/native-country-names" + }, + "time": "2025-02-24T19:27:45+00:00" + }, + { + "name": "laravel-lang/native-currency-names", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/native-currency-names.git", + "reference": "c63dea01b3ce58f709ae20bf5521b41ffca194c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/native-currency-names/zipball/c63dea01b3ce58f709ae20bf5521b41ffca194c9", + "reference": "c63dea01b3ce58f709ae20bf5521b41ffca194c9", + "shasum": "" + }, + "require": { + "dragon-code/support": "^6.11", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.2", + "pestphp/pest": "^2.24.3 || ^3.0", + "punic/punic": "^3.8", + "symfony/console": "^6.3 || ^7.0", + "symfony/process": "^6.3 || ^7.0", + "symfony/var-dumper": "^6.3 || ^7.0", + "vlucas/phpdotenv": "^5.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\NativeCurrencyNames\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The project contains native translations of currency names", + "keywords": [ + "Laravel-lang", + "currency", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/native-currency-names/issues", + "source": "https://github.com/Laravel-Lang/native-currency-names" + }, + "time": "2025-02-24T19:57:57+00:00" + }, + { + "name": "laravel-lang/native-locale-names", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/native-locale-names.git", + "reference": "9e08ad7c0e088618c67e94a321e62dc93eddfea5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/native-locale-names/zipball/9e08ad7c0e088618c67e94a321e62dc93eddfea5", + "reference": "9e08ad7c0e088618c67e94a321e62dc93eddfea5", + "shasum": "" + }, + "require": { + "dragon-code/support": "^6.11", + "ext-json": "*", + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.31 || ^11.0 || ^12.0", + "laravel-lang/locale-list": "^1.2", + "pestphp/pest": "^2.24.3", + "punic/punic": "^3.8", + "symfony/console": "^6.3 || ^7.0", + "symfony/process": "^6.3 || ^7.0", + "symfony/var-dumper": "^6.3 || ^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "LaravelLang\\NativeLocaleNames\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "The project contains native translations of locale names", + "keywords": [ + "Laravel-lang", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "translation", + "translations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/native-locale-names/issues", + "source": "https://github.com/Laravel-Lang/native-locale-names" + }, + "time": "2025-02-24T20:00:58+00:00" + }, + { + "name": "laravel-lang/publisher", + "version": "16.6.0", + "source": { + "type": "git", + "url": "https://github.com/Laravel-Lang/publisher.git", + "reference": "ab4f5364444065f95ca78c85c319f7786f67d7ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Laravel-Lang/publisher/zipball/ab4f5364444065f95ca78c85c319f7786f67d7ac", + "reference": "ab4f5364444065f95ca78c85c319f7786f67d7ac", + "shasum": "" + }, + "require": { + "composer/semver": "^3.4", + "dragon-code/pretty-array": "^4.1", + "dragon-code/support": "^6.11.3", + "ext-json": "*", + "illuminate/collections": "^10.0 || ^11.0 || ^12.0", + "illuminate/console": "^10.0 || ^11.0 || ^12.0", + "illuminate/support": "^10.0 || ^11.0 || ^12.0", + "laravel-lang/config": "^1.12", + "laravel-lang/locales": "^2.10", + "league/commonmark": "^2.4.1", + "league/config": "^1.2", + "php": "^8.1" + }, + "conflict": { + "laravel-lang/attributes": "<2.0", + "laravel-lang/http-statuses": "<3.0", + "laravel-lang/lang": "<11.0" + }, + "require-dev": { + "laravel-lang/json-fallback": "^2.2", + "orchestra/testbench": "^8.14 || ^9.0 || ^10.0", + "phpunit/phpunit": "^10.4.2 || ^11.0 || ^12.0", + "symfony/var-dumper": "^6.3.6 || ^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "LaravelLang\\Publisher\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "LaravelLang\\Publisher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andrey Helldar", + "email": "helldar@dragon-code.pro" + }, + { + "name": "Laravel-Lang Team", + "homepage": "https://laravel-lang.com" + } + ], + "description": "Localization publisher for your Laravel application", + "keywords": [ + "Laravel-lang", + "breeze", + "cashier", + "fortify", + "framework", + "i18n", + "jetstream", + "lang", + "languages", + "laravel", + "locale", + "locales", + "localization", + "localizations", + "lpm", + "lumen", + "nova", + "publisher", + "spark", + "trans", + "translation", + "translations", + "validations" + ], + "support": { + "issues": "https://github.com/Laravel-Lang/publisher/issues", + "source": "https://github.com/Laravel-Lang/publisher" + }, + "time": "2025-03-03T10:29:09+00:00" + }, + { + "name": "laravel-shift/blueprint", + "version": "v2.11.1", + "source": { + "type": "git", + "url": "https://github.com/laravel-shift/blueprint.git", + "reference": "f4071e3cf0c3c33ee6f5861b252910ef0030dee8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel-shift/blueprint/zipball/f4071e3cf0c3c33ee6f5861b252910ef0030dee8", + "reference": "f4071e3cf0c3c33ee6f5861b252910ef0030dee8", + "shasum": "" + }, + "require": { + "illuminate/console": "^10.38|^11.0|^12.0", + "illuminate/database": "^10.38|^11.0|^12.0", + "illuminate/filesystem": "^10.38|^11.0|^12.0", + "illuminate/support": "^10.38|^11.0|^12.0", + "laravel-shift/faker-registry": "^0.3.0", + "symfony/yaml": ">=6.2" + }, + "require-dev": { + "laravel/pint": "~1.18.0", + "mockery/mockery": "^1.4.4", + "orchestra/testbench": "^8.0|^9.0|^10.0", + "phpunit/phpunit": "^10.0|^11.5.3" + }, + "suggest": { + "jasonmccreary/laravel-test-assertions": "Required to use additional assertions in generated tests (^1.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Blueprint\\BlueprintServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Blueprint\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "An expressive, human readable code generation tool.", + "keywords": [ + "code generation", + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel-shift/blueprint/issues", + "source": "https://github.com/laravel-shift/blueprint/tree/v2.11.1" + }, + "time": "2025-02-11T19:59:49+00:00" + }, + { + "name": "laravel-shift/faker-registry", + "version": "v0.3.0", + "source": { + "type": "git", + "url": "https://github.com/laravel-shift/faker-registry.git", + "reference": "968ab023b6c76c2f67cc474ba6d81fce8ff869a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel-shift/faker-registry/zipball/968ab023b6c76c2f67cc474ba6d81fce8ff869a9", + "reference": "968ab023b6c76c2f67cc474ba6d81fce8ff869a9", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^8.0|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Shift\\Faker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jason McCreary", + "email": "jason@pureconcepts.net" + } + ], + "description": "A registry for generating Faker data from a name or data type.", + "support": { + "issues": "https://github.com/laravel-shift/faker-registry/issues", + "source": "https://github.com/laravel-shift/faker-registry/tree/v0.3.0" + }, + "time": "2023-11-24T15:54:02+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "f31f4980f52be17c4667f3eafe034e6826787db2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/f31f4980f52be17c4667f3eafe034e6826787db2", + "reference": "f31f4980f52be17c4667f3eafe034e6826787db2", + "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", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.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", + "phpstan/phpstan": "^1.10", + "symfony/var-dumper": "^6.3|^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2025-01-28T15:15:15+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.21.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/531fa0871fbde719c51b12afa3a443b8f4e4b425", + "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.68.5", + "illuminate/view": "^11.42.0", + "larastan/larastan": "^3.0.4", + "laravel-zero/framework": "^11.36.1", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3", + "pestphp/pest": "^2.36.0" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2025-02-18T03:18:57+00:00" + }, + { + "name": "laravel/sail", + "version": "v1.41.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/sail.git", + "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sail/zipball/fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec", + "reference": "fe1a4ada0abb5e4bd99eb4e4b0d87906c00cdeec", + "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", + "php": "^8.0", + "symfony/console": "^6.0|^7.0", + "symfony/yaml": "^6.0|^7.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "phpstan/phpstan": "^1.10" + }, + "bin": [ + "bin/sail" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sail\\SailServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Docker files for running a basic Laravel application.", + "keywords": [ + "docker", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/sail/issues", + "source": "https://github.com/laravel/sail" + }, + "time": "2025-01-24T15:45:36+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-02-12T12:17:51+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.6.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "86f003c132143d5a2ab214e19933946409e0cae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/86f003c132143d5a2ab214e19933946409e0cae7", + "reference": "86f003c132143d5a2ab214e19933946409e0cae7", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.16.0", + "nunomaduro/termwind": "^2.3.0", + "php": "^8.2.0", + "symfony/console": "^7.2.1" + }, + "conflict": { + "laravel/framework": "<11.39.1 || >=13.0.0", + "phpunit/phpunit": "<11.5.3 || >=12.0.0" + }, + "require-dev": { + "larastan/larastan": "^2.9.12", + "laravel/framework": "^11.39.1", + "laravel/pint": "^1.20.0", + "laravel/sail": "^1.40.0", + "laravel/sanctum": "^4.0.7", + "laravel/tinker": "^2.10.0", + "orchestra/testbench-core": "^9.9.2", + "pestphp/pest": "^3.7.3", + "sebastian/environment": "^6.1.0 || ^7.2.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-01-23T13:41:43+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "reference": "14d63fbcca18457e49c6f8bebaa91a87e8e188d7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.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/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.2" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "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.9" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-25T13:26:39+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "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" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-27T05:02:59+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "3946ac38410be7440186c6e74584f31b15107fc7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3946ac38410be7440186c6e74584f31b15107fc7", + "reference": "3946ac38410be7440186c6e74584f31b15107fc7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.0", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.9", + "phpunit/php-file-iterator": "^5.1.0", + "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.2", + "sebastian/comparator": "^6.3.0", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.0", + "sebastian/exporter": "^6.3.0", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.0", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "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.11" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-03-05T07:36:02+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca", + "reference": "ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-12T09:59:06+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/d4e47a769525c4dd38cea90e5dcd435ddbbc7115", + "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "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.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-01-06T10:28:19+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:54:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-05T09:17:50+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:10:34+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/461b9c5da241511a2a0e8f240814fb23ce5c0aac", + "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-09-17T13:12:04+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ac238f173df0c9c1120f862d0f599e17535a87ec", + "reference": "ac238f173df0c9c1120f862d0f599e17535a87ec", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-07T12:55:42+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "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" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.2" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..009a223 --- /dev/null +++ b/config/app.php @@ -0,0 +1,126 @@ + env('APP_NAME', 'Laravel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | the application so that it's available within Artisan commands. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. The timezone + | is set to "UTC" by default as it is suitable for most use cases. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by Laravel's translation / localization methods. This option can be + | set to any locale for which you plan to have translation strings. + | + */ + + 'locale' => env('APP_LOCALE', 'es'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'es'), + + 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. + | + */ + + 'cipher' => 'AES-256-CBC', + + 'key' => env('APP_KEY'), + + 'previous_keys' => [ + ...array_filter( + explode(',', env('APP_PREVIOUS_KEYS', '')) + ), + ], + + /* + |-------------------------------------------------------------------------- + | Maintenance Mode Driver + |-------------------------------------------------------------------------- + | + | These configuration options determine the driver used to determine and + | manage Laravel's "maintenance mode" status. The "cache" driver will + | allow maintenance mode to be controlled across multiple machines. + | + | Supported drivers: "file", "cache" + | + */ + + 'maintenance' => [ + 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), + 'store' => env('APP_MAINTENANCE_STORE', 'database'), + ], + +]; diff --git a/config/auth.php b/config/auth.php new file mode 100644 index 0000000..0ba5d5d --- /dev/null +++ b/config/auth.php @@ -0,0 +1,115 @@ + [ + 'guard' => env('AUTH_GUARD', 'web'), + 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | which utilizes session storage plus the Eloquent user provider. + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | Supported: "session" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + ], + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | If you have multiple user tables or models you may configure multiple + | providers to represent the model / table. These providers may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => env('AUTH_MODEL', App\Models\User::class), + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | These configuration options specify the behavior of Laravel's password + | reset functionality, including the table utilized for token storage + | and the user provider that is invoked to actually retrieve users. + | + | The expiry time is the number of minutes that each reset token will be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + | The throttle setting is the number of seconds a user must wait before + | generating more password reset tokens. This prevents the user from + | quickly generating a very large amount of password reset tokens. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), + 'expire' => 60, + 'throttle' => 60, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Password Confirmation Timeout + |-------------------------------------------------------------------------- + | + | Here you may define the amount of seconds before a password confirmation + | window expires and users are asked to re-enter their password via the + | confirmation screen. By default, the timeout lasts for three hours. + | + */ + + 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), + +]; diff --git a/config/blueprint.php b/config/blueprint.php new file mode 100644 index 0000000..a533b8d --- /dev/null +++ b/config/blueprint.php @@ -0,0 +1,177 @@ + 'App', + + /* + |-------------------------------------------------------------------------- + | Component Namespaces + |-------------------------------------------------------------------------- + | + | Blueprint promotes following Laravel conventions. As such, it generates + | components under the default namespaces. For example, models are under + | the `App` namespace. However, you may configure Blueprint to use + | your own custom namespace when generating these components. + | + */ + 'models_namespace' => 'Models', + + 'controllers_namespace' => 'Http\\Controllers', + + 'components_namespace' => 'Livewire', + + 'policy_namespace' => 'Policies', + + /* + |-------------------------------------------------------------------------- + | Application Path + |-------------------------------------------------------------------------- + | + | By default, Blueprint will save the generated application components + | under the files under the `app` folder. However, you may configure + | Blueprint to save these generated component under a custom path. + | + */ + 'app_path' => 'app', + + /* + |-------------------------------------------------------------------------- + | Generate PHPDocs + |-------------------------------------------------------------------------- + | + | Here you may enable generate PHPDocs for classes like Models. This + | not only serves as documentation, but also allows your IDE to + | map to the dynamic properties used by Laravel Models. + | + */ + 'generate_phpdocs' => false, + + /* + |-------------------------------------------------------------------------- + | Foreign Key Constraints + |-------------------------------------------------------------------------- + | + | Here you may enable Blueprint to always add foreign key constraints + | within the generated migration. This will relate these records + | together to add structure and integrity to your database. + | + | In addition, you may specify the action to perform `ON DELETE`. By + | default Blueprint will use `cascade`. However, you may set this + | to 'restrict', 'no_action', or 'null' as well as inline + | by defining your `foreign` key column with an `onDelete`. + | + */ + 'use_constraints' => false, + + 'on_delete' => 'cascade', + + 'on_update' => 'cascade', + + /* + |-------------------------------------------------------------------------- + | Fake Nullables + |-------------------------------------------------------------------------- + | + | By default, Blueprint will set fake data even for nullable columns + | within the generated model factories. However, you may disable + | this behavior if you prefer to only set required columns + | within your model factories. + | + */ + 'fake_nullables' => true, + + /* + |-------------------------------------------------------------------------- + | Use Guarded + |-------------------------------------------------------------------------- + | + | By default, Blueprint will set the `fillable` property within generated + | models with the defined columns. These are set to provide a foundation + | for mass assignment protection provided by Laravel. However, you may + | configure Blueprint to instead set an empty `guarded` property to + | generated "unguarded" models. + | + */ + 'use_guarded' => false, + + /* + |-------------------------------------------------------------------------- + | Singular route names + |-------------------------------------------------------------------------- + | + | By default, Blueprint will `kebab-case` the plural name of the controller + | for the route name. If you would like to ensure a singular route name + | is used for controllers, you may set this to `true`. + | + */ + 'singular_routes' => false, + + /* + |-------------------------------------------------------------------------- + | Constructor Property Promotion + |-------------------------------------------------------------------------- + | + | By default, Blueprint generates class properties explicitly. You may enable + | this option to have Blueprint generate code for classes which contain a + | constructor to set properties with "constructor property promotion". + | + */ + 'property_promotion' => false, + + /* + |-------------------------------------------------------------------------- + | Generate Resource Collection Classes + |-------------------------------------------------------------------------- + | + | By default, Blueprint generates resource collection classes to manage resource + | collections (e.g. `PostResourceCollection`). You may disable this option to + | generate only resource classes and use their `collection` method instead. + | + */ + 'generate_resource_collection_classes' => true, + + /* + |-------------------------------------------------------------------------- + | Generators + |-------------------------------------------------------------------------- + | + | Blueprint will automatically register this default array of Generator classes. + | However, you may configure Blueprint to use a custom Generator class to grant + | expanded functionality to Blueprint. + | + | Your custom Generator class MUST implement the 'Blueprint\Contracts\Generator' interface. + | + */ + 'generators' => [ + 'controller' => \Blueprint\Generators\ControllerGenerator::class, + 'factory' => \Blueprint\Generators\FactoryGenerator::class, + 'migration' => \Blueprint\Generators\MigrationGenerator::class, + 'model' => \Blueprint\Generators\ModelGenerator::class, + 'route' => \Blueprint\Generators\RouteGenerator::class, + 'seeder' => \Blueprint\Generators\SeederGenerator::class, + 'test' => \Blueprint\Generators\PhpUnitTestGenerator::class, + // 'test' => \Blueprint\Generators\PestTestGenerator::class, + 'event' => \Blueprint\Generators\Statements\EventGenerator::class, + 'form_request' => \Blueprint\Generators\Statements\FormRequestGenerator::class, + 'job' => \Blueprint\Generators\Statements\JobGenerator::class, + 'mail' => \Blueprint\Generators\Statements\MailGenerator::class, + 'notification' => \Blueprint\Generators\Statements\NotificationGenerator::class, + 'resource' => \Blueprint\Generators\Statements\ResourceGenerator::class, + 'view' => \Blueprint\Generators\Statements\ViewGenerator::class, + 'inertia_page' => \Blueprint\Generators\Statements\InertiaPageGenerator::class, + 'policy' => \Blueprint\Generators\PolicyGenerator::class, + ], + +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..925f7d2 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,108 @@ + env('CACHE_STORE', 'database'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + | Supported drivers: "array", "database", "file", "memcached", + | "redis", "dynamodb", "octane", "null" + | + */ + + 'stores' => [ + + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_CACHE_CONNECTION'), + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), + 'lock_table' => env('DB_CACHE_LOCK_TABLE'), + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + 'lock_path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), + 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), + ], + + 'dynamodb' => [ + 'driver' => 'dynamodb', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), + 'endpoint' => env('DYNAMODB_ENDPOINT'), + ], + + 'octane' => [ + 'driver' => 'octane', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing the APC, database, memcached, Redis, and DynamoDB cache + | stores, there might be other applications using the same cache. For + | that reason, you may prefix every cache key to avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), + +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..8910562 --- /dev/null +++ b/config/database.php @@ -0,0 +1,174 @@ + env('DB_CONNECTION', 'sqlite'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Below are all of the database connections defined for your application. + | An example configuration is provided for each database system which + | is supported by Laravel. You're free to add / remove connections. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DB_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + 'busy_timeout' => null, + 'journal_mode' => null, + 'synchronous' => null, + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'mariadb' => [ + 'driver' => 'mariadb', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + // 'encrypt' => env('DB_ENCRYPT', 'yes'), + // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run on the database. + | + */ + + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as Memcached. You may define your connection settings here. + | + */ + + 'redis' => [ + + 'client' => env('REDIS_CLIENT', 'phpredis'), + + 'options' => [ + 'cluster' => env('REDIS_CLUSTER', 'redis'), + 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), + 'persistent' => env('REDIS_PERSISTENT', false), + ], + + 'default' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_DB', '0'), + ], + + 'cache' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_CACHE_DB', '1'), + ], + + ], + +]; diff --git a/config/filament.php b/config/filament.php new file mode 100644 index 0000000..b5d18fb --- /dev/null +++ b/config/filament.php @@ -0,0 +1,100 @@ + 'es', + /* + |-------------------------------------------------------------------------- + | Broadcasting + |-------------------------------------------------------------------------- + | + | By uncommenting the Laravel Echo configuration, you may connect Filament + | to any Pusher-compatible websockets server. + | + | This will allow your users to receive real-time notifications. + | + */ + + + 'brand' => [ + 'logo' => env('FILAMENT_LOGO', null), + 'colors' => [ + 'primary' => env('FILAMENT_PRIMARY_COLOR', '#3498db'), + 'secondary' => env('FILAMENT_SECONDARY_COLOR', '#2ecc71'), + ], +], + + + 'broadcasting' => [ + + // 'echo' => [ + // 'broadcaster' => 'pusher', + // 'key' => env('VITE_PUSHER_APP_KEY'), + // 'cluster' => env('VITE_PUSHER_APP_CLUSTER'), + // 'wsHost' => env('VITE_PUSHER_HOST'), + // 'wsPort' => env('VITE_PUSHER_PORT'), + // 'wssPort' => env('VITE_PUSHER_PORT'), + // 'authEndpoint' => '/broadcasting/auth', + // 'disableStats' => true, + // 'encrypted' => true, + // 'forceTLS' => true, + // ], + + ], + + /* + |-------------------------------------------------------------------------- + | Default Filesystem Disk + |-------------------------------------------------------------------------- + | + | This is the storage disk Filament will use to store files. You may use + | any of the disks defined in the `config/filesystems.php`. + | + */ + + 'default_filesystem_disk' => env('FILAMENT_FILESYSTEM_DISK', 'public'), + + /* + |-------------------------------------------------------------------------- + | Assets Path + |-------------------------------------------------------------------------- + | + | This is the directory where Filament's assets will be published to. It + | is relative to the `public` directory of your Laravel application. + | + | After changing the path, you should run `php artisan filament:assets`. + | + */ + + 'assets_path' => null, + + /* + |-------------------------------------------------------------------------- + | Cache Path + |-------------------------------------------------------------------------- + | + | This is the directory that Filament will use to store cache files that + | are used to optimize the registration of components. + | + | After changing the path, you should run `php artisan filament:cache-components`. + | + */ + + 'cache_path' => base_path('bootstrap/cache/filament'), + + /* + |-------------------------------------------------------------------------- + | Livewire Loading Delay + |-------------------------------------------------------------------------- + | + | This sets the delay before loading indicators appear. + | + | Setting this to 'none' makes indicators appear immediately, which can be + | desirable for high-latency connections. Setting it to 'default' applies + | Livewire's standard 200ms delay. + | + */ + + 'livewire_loading_delay' => 'default', + +]; diff --git a/config/filesystems.php b/config/filesystems.php new file mode 100644 index 0000000..3d671bd --- /dev/null +++ b/config/filesystems.php @@ -0,0 +1,80 @@ + env('FILESYSTEM_DISK', 'local'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Below you may configure as many filesystem disks as necessary, and you + | may even configure multiple disks for the same driver. Examples for + | most supported storage drivers are configured here for reference. + | + | Supported drivers: "local", "ftp", "sftp", "s3" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app/private'), + 'serve' => true, + 'throw' => false, + 'report' => false, + ], + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', + 'throw' => false, + 'report' => false, + ], + + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + 'url' => env('AWS_URL'), + 'endpoint' => env('AWS_ENDPOINT'), + 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), + 'throw' => false, + 'report' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Symbolic Links + |-------------------------------------------------------------------------- + | + | Here you may configure the symbolic links that will be created when the + | `storage:link` Artisan command is executed. The array keys should be + | the locations of the links and the values should be their targets. + | + */ + + 'links' => [ + public_path('storage') => storage_path('app/public'), + ], + +]; diff --git a/config/hashing.php b/config/hashing.php new file mode 100644 index 0000000..d1ab33d --- /dev/null +++ b/config/hashing.php @@ -0,0 +1,48 @@ + 'bcrypt', + + /* + |-------------------------------------------------------------------------- + | Bcrypt Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Bcrypt algorithm. + | + */ + + 'bcrypt' => [ + 'rounds' => env('BCRYPT_ROUNDS', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Argon Options + |-------------------------------------------------------------------------- + | + | These options are used when the Argon2 algorithm is selected for + | password hashing. You can configure how much memory and time + | is used when hashing the passwords using Argon. + | + */ + + 'argon' => [ + 'memory' => 65536, + 'threads' => 1, + 'time' => 4, + ], + +]; diff --git a/config/livewire.php b/config/livewire.php new file mode 100644 index 0000000..0d2ba89 --- /dev/null +++ b/config/livewire.php @@ -0,0 +1,160 @@ + 'App\\Livewire', + + /* + |--------------------------------------------------------------------------- + | View Path + |--------------------------------------------------------------------------- + | + | This value is used to specify where Livewire component Blade templates are + | stored when running file creation commands like `artisan make:livewire`. + | It is also used if you choose to omit a component's render() method. + | + */ + + 'view_path' => resource_path('views/livewire'), + + /* + |--------------------------------------------------------------------------- + | Layout + |--------------------------------------------------------------------------- + | The view that will be used as the layout when rendering a single component + | as an entire page via `Route::get('/post/create', CreatePost::class);`. + | In this case, the view returned by CreatePost will render into $slot. + | + */ + + 'layout' => 'components.layouts.app', + + /* + |--------------------------------------------------------------------------- + | Lazy Loading Placeholder + |--------------------------------------------------------------------------- + | Livewire allows you to lazy load components that would otherwise slow down + | the initial page load. Every component can have a custom placeholder or + | you can define the default placeholder view for all components below. + | + */ + + 'lazy_placeholder' => null, + + /* + |--------------------------------------------------------------------------- + | Temporary File Uploads + |--------------------------------------------------------------------------- + | + | Livewire handles file uploads by storing uploads in a temporary directory + | before the file is stored permanently. All file uploads are directed to + | a global endpoint for temporary storage. You may configure this below: + | + */ + + 'temporary_file_upload' => [ + 'disk' => null, // Example: 'local', 's3' | Default: 'default' + 'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB) + 'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp' + 'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1' + 'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs... + 'png', 'gif', 'bmp', 'svg', 'wav', 'mp4', + 'mov', 'avi', 'wmv', 'mp3', 'm4a', + 'jpg', 'jpeg', 'mpga', 'webp', 'wma', + ], + 'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated... + 'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs... + ], + + /* + |--------------------------------------------------------------------------- + | Render On Redirect + |--------------------------------------------------------------------------- + | + | This value determines if Livewire will run a component's `render()` method + | after a redirect has been triggered using something like `redirect(...)` + | Setting this to true will render the view once more before redirecting + | + */ + + 'render_on_redirect' => false, + + /* + |--------------------------------------------------------------------------- + | Eloquent Model Binding + |--------------------------------------------------------------------------- + | + | Previous versions of Livewire supported binding directly to eloquent model + | properties using wire:model by default. However, this behavior has been + | deemed too "magical" and has therefore been put under a feature flag. + | + */ + + 'legacy_model_binding' => false, + + /* + |--------------------------------------------------------------------------- + | Auto-inject Frontend Assets + |--------------------------------------------------------------------------- + | + | By default, Livewire automatically injects its JavaScript and CSS into the + | and of pages containing Livewire components. By disabling + | this behavior, you need to use @livewireStyles and @livewireScripts. + | + */ + + 'inject_assets' => true, + + /* + |--------------------------------------------------------------------------- + | Navigate (SPA mode) + |--------------------------------------------------------------------------- + | + | By adding `wire:navigate` to links in your Livewire application, Livewire + | will prevent the default link handling and instead request those pages + | via AJAX, creating an SPA-like effect. Configure this behavior here. + | + */ + + 'navigate' => [ + 'show_progress_bar' => true, + 'progress_bar_color' => '#2299dd', + ], + + /* + |--------------------------------------------------------------------------- + | HTML Morph Markers + |--------------------------------------------------------------------------- + | + | Livewire intelligently "morphs" existing HTML into the newly rendered HTML + | after each update. To make this process more reliable, Livewire injects + | "markers" into the rendered Blade surrounding @if, @class & @foreach. + | + */ + + 'inject_morph_markers' => true, + + /* + |--------------------------------------------------------------------------- + | Pagination Theme + |--------------------------------------------------------------------------- + | + | When enabling Livewire's pagination feature by using the `WithPagination` + | trait, Livewire will use Tailwind templates to render pagination views + | on the page. If you want Bootstrap CSS, you can specify: "bootstrap" + | + */ + + 'pagination_theme' => 'tailwind', +]; diff --git a/config/logging.php b/config/logging.php new file mode 100644 index 0000000..8d94292 --- /dev/null +++ b/config/logging.php @@ -0,0 +1,132 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Deprecations Log Channel + |-------------------------------------------------------------------------- + | + | This option controls the log channel that should be used to log warnings + | regarding deprecated PHP and library features. This allows you to get + | your application ready for upcoming major versions of dependencies. + | + */ + + 'deprecations' => [ + 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), + 'trace' => env('LOG_DEPRECATIONS_TRACE', false), + ], + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Laravel + | utilizes the Monolog PHP logging library, which includes a variety + | of powerful log handlers and formatters that you're free to use. + | + | Available drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", "custom", "stack" + | + */ + + 'channels' => [ + + 'stack' => [ + 'driver' => 'stack', + 'channels' => explode(',', env('LOG_STACK', 'single')), + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => env('LOG_DAILY_DAYS', 14), + 'replace_placeholders' => true, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), + 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), + 'level' => env('LOG_LEVEL', 'critical'), + 'replace_placeholders' => true, + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => StreamHandler::class, + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'with' => [ + 'stream' => 'php://stderr', + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), + 'replace_placeholders' => true, + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/laravel.log'), + ], + + ], + +]; diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000..756305b --- /dev/null +++ b/config/mail.php @@ -0,0 +1,116 @@ + env('MAIL_MAILER', 'log'), + + /* + |-------------------------------------------------------------------------- + | Mailer Configurations + |-------------------------------------------------------------------------- + | + | Here you may configure all of the mailers used by your application plus + | their respective settings. Several examples have been configured for + | you and you are free to add your own as your application requires. + | + | Laravel supports a variety of mail "transport" drivers that can be used + | when delivering an email. You may specify which one you're using for + | your mailers below. You may also add additional mailers if needed. + | + | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", + | "postmark", "resend", "log", "array", + | "failover", "roundrobin" + | + */ + + 'mailers' => [ + + 'smtp' => [ + 'transport' => 'smtp', + 'scheme' => env('MAIL_SCHEME'), + 'url' => env('MAIL_URL'), + 'host' => env('MAIL_HOST', '127.0.0.1'), + 'port' => env('MAIL_PORT', 2525), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'postmark' => [ + 'transport' => 'postmark', + // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), + // 'client' => [ + // 'timeout' => 5, + // ], + ], + + 'resend' => [ + 'transport' => 'resend', + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), + ], + + 'log' => [ + 'transport' => 'log', + 'channel' => env('MAIL_LOG_CHANNEL'), + ], + + 'array' => [ + 'transport' => 'array', + ], + + 'failover' => [ + 'transport' => 'failover', + 'mailers' => [ + 'smtp', + 'log', + ], + ], + + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'ses', + 'postmark', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all emails sent by your application to be sent from + | the same address. Here you may specify a name and address that is + | used globally for all emails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + +]; diff --git a/config/permission.php b/config/permission.php new file mode 100644 index 0000000..8e84e9d --- /dev/null +++ b/config/permission.php @@ -0,0 +1,202 @@ + [ + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * Eloquent model should be used to retrieve your permissions. Of course, it + * is often just the "Permission" model but you may use whatever you like. + * + * The model you want to use as a Permission model needs to implement the + * `Spatie\Permission\Contracts\Permission` contract. + */ + + 'permission' => Spatie\Permission\Models\Permission::class, + + /* + * When using the "HasRoles" trait from this package, we need to know which + * Eloquent model should be used to retrieve your roles. Of course, it + * is often just the "Role" model but you may use whatever you like. + * + * The model you want to use as a Role model needs to implement the + * `Spatie\Permission\Contracts\Role` contract. + */ + + 'role' => Spatie\Permission\Models\Role::class, + + ], + + 'table_names' => [ + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'roles' => 'roles', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your permissions. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'permissions' => 'permissions', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your models permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_permissions' => 'model_has_permissions', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your models roles. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_roles' => 'model_has_roles', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'role_has_permissions' => 'role_has_permissions', + ], + + 'column_names' => [ + /* + * Change this if you want to name the related pivots other than defaults + */ + 'role_pivot_key' => null, // default 'role_id', + 'permission_pivot_key' => null, // default 'permission_id', + + /* + * Change this if you want to name the related model primary key other than + * `model_id`. + * + * For example, this would be nice if your primary keys are all UUIDs. In + * that case, name this `model_uuid`. + */ + + 'model_morph_key' => 'model_id', + + /* + * Change this if you want to use the teams feature and your related model's + * foreign key is other than `team_id`. + */ + + 'team_foreign_key' => 'team_id', + ], + + /* + * When set to true, the method for checking permissions will be registered on the gate. + * Set this to false if you want to implement custom logic for checking permissions. + */ + + 'register_permission_check_method' => true, + + /* + * When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered + * this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated + * NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it. + */ + 'register_octane_reset_listener' => false, + + /* + * Events will fire when a role or permission is assigned/unassigned: + * \Spatie\Permission\Events\RoleAttached + * \Spatie\Permission\Events\RoleDetached + * \Spatie\Permission\Events\PermissionAttached + * \Spatie\Permission\Events\PermissionDetached + * + * To enable, set to true, and then create listeners to watch these events. + */ + 'events_enabled' => false, + + /* + * Teams Feature. + * When set to true the package implements teams using the 'team_foreign_key'. + * If you want the migrations to register the 'team_foreign_key', you must + * set this to true before doing the migration. + * If you already did the migration then you must make a new migration to also + * add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions' + * (view the latest version of this package's migration file) + */ + + 'teams' => false, + + /* + * The class to use to resolve the permissions team id + */ + 'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class, + + /* + * Passport Client Credentials Grant + * When set to true the package will use Passports Client to check permissions + */ + + 'use_passport_client_credentials' => false, + + /* + * When set to true, the required permission names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_permission_in_exception' => false, + + /* + * When set to true, the required role names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_role_in_exception' => false, + + /* + * By default wildcard permission lookups are disabled. + * See documentation to understand supported syntax. + */ + + 'enable_wildcard_permission' => false, + + /* + * The class to use for interpreting wildcard permissions. + * If you need to modify delimiters, override the class and specify its name here. + */ + // 'permission.wildcard_permission' => Spatie\Permission\WildcardPermission::class, + + /* Cache-specific settings */ + + 'cache' => [ + + /* + * By default all permissions are cached for 24 hours to speed up performance. + * When permissions or roles are updated the cache is flushed automatically. + */ + + 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + + /* + * The cache key used to store all permissions. + */ + + 'key' => 'spatie.permission.cache', + + /* + * You may optionally indicate a specific cache driver to use for permission and + * role caching using any of the `store` drivers listed in the cache.php config + * file. Using 'default' here means to use the `default` set in cache.php. + */ + + 'store' => 'default', + ], +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..116bd8d --- /dev/null +++ b/config/queue.php @@ -0,0 +1,112 @@ + env('QUEUE_CONNECTION', 'database'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Laravel. You're also free to add more. + | + | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'after_commit' => false, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), + 'queue' => env('BEANSTALKD_QUEUE', 'default'), + 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), + 'block_for' => 0, + 'after_commit' => false, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'default'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'after_commit' => false, + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), + 'block_for' => null, + 'after_commit' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'job_batches', + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control how and where failed jobs are stored. Laravel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..27a3617 --- /dev/null +++ b/config/services.php @@ -0,0 +1,38 @@ + [ + 'token' => env('POSTMARK_TOKEN'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'resend' => [ + 'key' => env('RESEND_KEY'), + ], + + 'slack' => [ + 'notifications' => [ + 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), + 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), + ], + ], + +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..ba0aa60 --- /dev/null +++ b/config/session.php @@ -0,0 +1,217 @@ + env('SESSION_DRIVER', 'database'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to expire immediately when the browser is closed then you may + | indicate that via the expire_on_close configuration option. + | + */ + + 'lifetime' => (int) env('SESSION_LIFETIME', 120), + + 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it's stored. All encryption is performed + | automatically by Laravel and you may use the session like normal. + | + */ + + 'encrypt' => env('SESSION_ENCRYPT', false), + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When utilizing the "file" session driver, the session files are placed + | on disk. The default storage location is defined here; however, you + | are free to provide another location where they should be stored. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => env('SESSION_CONNECTION'), + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table to + | be used to store sessions. Of course, a sensible default is defined + | for you; however, you're welcome to change this to another table. + | + */ + + 'table' => env('SESSION_TABLE', 'sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using one of the framework's cache driven session backends, you may + | define the cache store which should be used to store the session data + | between requests. This must match one of your defined cache stores. + | + | Affects: "apc", "dynamodb", "memcached", "redis" + | + */ + + 'store' => env('SESSION_STORE'), + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the session cookie that is created by + | the framework. Typically, you should not need to change this value + | since doing so does not grant a meaningful security improvement. + | + */ + + 'cookie' => env( + 'SESSION_COOKIE', + Str::slug(env('APP_NAME', 'laravel'), '_').'_session' + ), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application, but you're free to change this when necessary. + | + */ + + 'path' => env('SESSION_PATH', '/'), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | This value determines the domain and subdomains the session cookie is + | available to. By default, the cookie will be available to the root + | domain and all subdomains. Typically, this shouldn't be changed. + | + */ + + 'domain' => env('SESSION_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you when it can't be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE'), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. It's unlikely you should disable this option. + | + */ + + 'http_only' => env('SESSION_HTTP_ONLY', true), + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | will set this value to "lax" to permit secure cross-site requests. + | + | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value + | + | Supported: "lax", "strict", "none", null + | + */ + + 'same_site' => env('SESSION_SAME_SITE', 'lax'), + + /* + |-------------------------------------------------------------------------- + | Partitioned Cookies + |-------------------------------------------------------------------------- + | + | Setting this value to true will tie the cookie to the top-level site for + | a cross-site context. Partitioned cookies are accepted by the browser + | when flagged "secure" and the Same-Site attribute is set to "none". + | + */ + + 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), + +]; diff --git a/database/.gitignore b/database/.gitignore new file mode 100644 index 0000000..9b19b93 --- /dev/null +++ b/database/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/database/factories/AuthUserFactory.php b/database/factories/AuthUserFactory.php new file mode 100644 index 0000000..8fb57dc --- /dev/null +++ b/database/factories/AuthUserFactory.php @@ -0,0 +1,36 @@ + fake()->userName(), + 'password' => fake()->password(), + 'last_login' => fake()->dateTime(), + 'is_superuser' => fake()->boolean(), + 'first_name' => fake()->firstName(), + 'last_name' => fake()->lastName(), + 'email' => fake()->safeEmail(), + 'is_staff' => fake()->boolean(), + 'is_active' => fake()->boolean(), + 'date_joined' => fake()->dateTime(), + ]; + } +} diff --git a/database/factories/CajaFactory.php b/database/factories/CajaFactory.php new file mode 100644 index 0000000..122dcb6 --- /dev/null +++ b/database/factories/CajaFactory.php @@ -0,0 +1,31 @@ + fake()->randomFloat(2, 0, 99999999.99), + 'monto_final' => fake()->randomFloat(2, 0, 99999999.99), + 'fecha_apertura' => fake()->dateTime(), + 'fecha_cierre' => fake()->dateTime(), + 'estado' => fake()->randomElement(["Abierta","Cerrada"]), + ]; + } +} diff --git a/database/factories/CategoriaFactory.php b/database/factories/CategoriaFactory.php new file mode 100644 index 0000000..3e99a6f --- /dev/null +++ b/database/factories/CategoriaFactory.php @@ -0,0 +1,28 @@ + fake()->regexify('[A-Za-z0-9]{255}'), + 'descripcion' => fake()->text(), + ]; + } +} diff --git a/database/factories/ClienteFactory.php b/database/factories/ClienteFactory.php new file mode 100644 index 0000000..576d84d --- /dev/null +++ b/database/factories/ClienteFactory.php @@ -0,0 +1,32 @@ + fake()->regexify('[A-Za-z0-9]{255}'), + 'correo' => fake()->regexify('[A-Za-z0-9]{255}'), + 'telefono' => fake()->regexify('[A-Za-z0-9]{20}'), + 'direccion' => fake()->text(), + 'tipo_documento' => fake()->randomElement(["DNI","RUC","PASAPORTE"]), + 'numero_documento' => fake()->regexify('[A-Za-z0-9]{20}'), + ]; + } +} diff --git a/database/factories/ColorFactory.php b/database/factories/ColorFactory.php new file mode 100644 index 0000000..b79f7c6 --- /dev/null +++ b/database/factories/ColorFactory.php @@ -0,0 +1,28 @@ + fake()->name(), + 'hex_code' => fake()->regexify('[A-Za-z0-9]{7}'), + ]; + } +} diff --git a/database/factories/CompraFactory.php b/database/factories/CompraFactory.php new file mode 100644 index 0000000..3382106 --- /dev/null +++ b/database/factories/CompraFactory.php @@ -0,0 +1,31 @@ + fake()->dateTime(), + 'proveedor_id' => Proveedore::factory(), + 'total' => fake()->randomFloat(2, 0, 99999999.99), + 'estado' => fake()->randomElement(["Recibida","Pendiente","Anulada"]), + ]; + } +} diff --git a/database/factories/DetalleCompraFactory.php b/database/factories/DetalleCompraFactory.php new file mode 100644 index 0000000..fb4ca6d --- /dev/null +++ b/database/factories/DetalleCompraFactory.php @@ -0,0 +1,33 @@ + Compra::factory(), + 'producto_id' => Producto::factory(), + 'cantidad' => fake()->numberBetween(-10000, 10000), + 'precio_unitario' => fake()->randomFloat(2, 0, 99999999.99), + 'subtotal' => fake()->randomFloat(2, 0, 99999999.99), + ]; + } +} diff --git a/database/factories/DetalleVentaFactory.php b/database/factories/DetalleVentaFactory.php new file mode 100644 index 0000000..7dd398f --- /dev/null +++ b/database/factories/DetalleVentaFactory.php @@ -0,0 +1,33 @@ + Venta::factory(), + 'producto_id' => Producto::factory(), + 'cantidad' => fake()->numberBetween(-10000, 10000), + 'precio_unitario' => fake()->randomFloat(2, 0, 99999999.99), + 'subtotal' => fake()->randomFloat(2, 0, 99999999.99), + ]; + } +} diff --git a/database/factories/InventarioFactory.php b/database/factories/InventarioFactory.php new file mode 100644 index 0000000..9bc88db --- /dev/null +++ b/database/factories/InventarioFactory.php @@ -0,0 +1,31 @@ + Producto::factory(), + 'stock_actual' => fake()->numberBetween(-10000, 10000), + 'stock_minimo' => fake()->numberBetween(-10000, 10000), + 'ubicacion' => fake()->regexify('[A-Za-z0-9]{255}'), + ]; + } +} diff --git a/database/factories/MovimientoCajaFactory.php b/database/factories/MovimientoCajaFactory.php new file mode 100644 index 0000000..5c498ab --- /dev/null +++ b/database/factories/MovimientoCajaFactory.php @@ -0,0 +1,32 @@ + Caja::factory(), + 'tipo' => fake()->randomElement(["Ingreso","Egreso"]), + 'monto' => fake()->randomFloat(2, 0, 99999999.99), + 'descripcion' => fake()->text(), + 'fecha' => fake()->dateTime(), + ]; + } +} diff --git a/database/factories/ProductVariantFactory.php b/database/factories/ProductVariantFactory.php new file mode 100644 index 0000000..37f5d05 --- /dev/null +++ b/database/factories/ProductVariantFactory.php @@ -0,0 +1,31 @@ + fake()->word(), + 'color_id' => fake()->word(), + 'size_id' => fake()->word(), + 'stock' => fake()->numberBetween(-10000, 10000), + 'sku' => fake()->regexify('[A-Za-z0-9]{50}'), + ]; + } +} diff --git a/database/factories/ProductoFactory.php b/database/factories/ProductoFactory.php new file mode 100644 index 0000000..20fd8cf --- /dev/null +++ b/database/factories/ProductoFactory.php @@ -0,0 +1,34 @@ + fake()->regexify('[A-Za-z0-9]{100}'), + 'descripcion' => fake()->text(), + 'codigo_barras' => fake()->regexify('[A-Za-z0-9]{50}'), + 'precio_compra' => fake()->word(), + 'precio_venta' => fake()->word(), + 'stock' => fake()->numberBetween(-10000, 10000), + 'categoria_id' => fake()->word(), + 'estado' => fake()->boolean(), + ]; + } +} diff --git a/database/factories/ProveedorFactory.php b/database/factories/ProveedorFactory.php new file mode 100644 index 0000000..f8cc0a4 --- /dev/null +++ b/database/factories/ProveedorFactory.php @@ -0,0 +1,31 @@ + fake()->regexify('[A-Za-z0-9]{255}'), + 'contacto' => fake()->regexify('[A-Za-z0-9]{255}'), + 'telefono' => fake()->regexify('[A-Za-z0-9]{20}'), + 'correo' => fake()->regexify('[A-Za-z0-9]{255}'), + 'direccion' => fake()->text(), + ]; + } +} diff --git a/database/factories/RoleFactory.php b/database/factories/RoleFactory.php new file mode 100644 index 0000000..5777ca0 --- /dev/null +++ b/database/factories/RoleFactory.php @@ -0,0 +1,28 @@ + fake()->name(), + 'description' => fake()->text(), + ]; + } +} diff --git a/database/factories/SettingFactory.php b/database/factories/SettingFactory.php new file mode 100644 index 0000000..e2c52d6 --- /dev/null +++ b/database/factories/SettingFactory.php @@ -0,0 +1,32 @@ + fake()->word(), + 'description' => fake()->text(), + 'primary_color' => fake()->word(), + 'secondary_color' => fake()->word(), + 'created_at' => fake()->dateTime(), + 'updated_at' => fake()->dateTime(), + ]; + } +} diff --git a/database/factories/SizeFactory.php b/database/factories/SizeFactory.php new file mode 100644 index 0000000..2706def --- /dev/null +++ b/database/factories/SizeFactory.php @@ -0,0 +1,27 @@ + fake()->name(), + ]; + } +} diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 0000000..6bbd977 --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,29 @@ + fake()->name(), + 'email' => fake()->safeEmail(), + 'password' => fake()->password(), + ]; + } +} diff --git a/database/factories/VentaFactory.php b/database/factories/VentaFactory.php new file mode 100644 index 0000000..f89910e --- /dev/null +++ b/database/factories/VentaFactory.php @@ -0,0 +1,32 @@ + fake()->dateTime(), + 'cliente_id' => Cliente::factory(), + 'total' => fake()->randomFloat(2, 0, 99999999.99), + 'tipo_pago' => fake()->randomElement(["Efectivo","Tarjeta","Transferencia"]), + 'estado' => fake()->randomElement(["Pagado","Pendiente","Anulado"]), + ]; + } +} diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php new file mode 100644 index 0000000..05fb5d9 --- /dev/null +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -0,0 +1,49 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->rememberToken(); + $table->timestamps(); + }); + + Schema::create('password_reset_tokens', function (Blueprint $table) { + $table->string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + + Schema::create('sessions', function (Blueprint $table) { + $table->string('id')->primary(); + $table->foreignId('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + Schema::dropIfExists('password_reset_tokens'); + Schema::dropIfExists('sessions'); + } +}; diff --git a/database/migrations/0001_01_01_000001_create_cache_table.php b/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..b9c106b --- /dev/null +++ b/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration'); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/database/migrations/0001_01_01_000002_create_jobs_table.php b/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..425e705 --- /dev/null +++ b/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,57 @@ +id(); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + + Schema::create('job_batches', function (Blueprint $table) { + $table->string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->longText('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->string('uuid')->unique(); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->longText('exception'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + Schema::dropIfExists('job_batches'); + Schema::dropIfExists('failed_jobs'); + } +}; diff --git a/database/migrations/2025_03_05_235357_create_role_user_table.php b/database/migrations/2025_03_05_235357_create_role_user_table.php new file mode 100644 index 0000000..e8a7925 --- /dev/null +++ b/database/migrations/2025_03_05_235357_create_role_user_table.php @@ -0,0 +1,27 @@ +foreignId('role_id'); + $table->foreignId('user_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('role_user'); + } +}; diff --git a/database/migrations/2025_03_06_005521_create_settings_table.php b/database/migrations/2025_03_06_005521_create_settings_table.php new file mode 100644 index 0000000..d6327cb --- /dev/null +++ b/database/migrations/2025_03_06_005521_create_settings_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('logo')->nullable(); + $table->text('description')->nullable(); + $table->string('primary_color')->nullable(); + $table->string('secondary_color')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('settings'); + } +}; diff --git a/database/migrations/2025_03_29_002923_create_categorias_table.php b/database/migrations/2025_03_29_002923_create_categorias_table.php new file mode 100644 index 0000000..ca72172 --- /dev/null +++ b/database/migrations/2025_03_29_002923_create_categorias_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('nombre', 255); + $table->text('descripcion')->nullable(); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down() + { + Schema::table('productos', function (Blueprint $table) { + $table->dropForeign(['categoria_id']); // Ajusta el nombre si es diferente + }); + + Schema::dropIfExists('categorias'); + } + +}; diff --git a/database/migrations/2025_03_29_002924_create_clientes_table.php b/database/migrations/2025_03_29_002924_create_clientes_table.php new file mode 100644 index 0000000..32f746f --- /dev/null +++ b/database/migrations/2025_03_29_002924_create_clientes_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('nombre', 255); + $table->string('correo', 255)->nullable(); + $table->string('telefono', 20)->nullable(); + $table->string('numero_documento', 20); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('clientes'); + } +}; diff --git a/database/migrations/2025_03_29_002925_create_proveedors_table.php b/database/migrations/2025_03_29_002925_create_proveedors_table.php new file mode 100644 index 0000000..3d4f65e --- /dev/null +++ b/database/migrations/2025_03_29_002925_create_proveedors_table.php @@ -0,0 +1,36 @@ +id(); + $table->string('nombre', 255); + $table->string('contacto', 255)->nullable(); + $table->string('telefono', 20)->nullable(); + $table->string('correo', 255)->unique()->nullable(); + $table->text('direccion')->nullable(); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('proveedors'); + } +}; diff --git a/database/migrations/2025_03_29_002926_create_productos_table.php b/database/migrations/2025_03_29_002926_create_productos_table.php new file mode 100644 index 0000000..b8feed0 --- /dev/null +++ b/database/migrations/2025_03_29_002926_create_productos_table.php @@ -0,0 +1,55 @@ +id(); + $table->string('nombre', 100); + $table->text('descripcion'); + $table->string('codigo_barras', 50)->unique(); + $table->string('precio_compra'); + $table->string('precio_venta'); + $table->integer('stock')->default(0); + $table->unsignedBigInteger('categoria_id'); // Cambio a unsignedBigInteger + $table->boolean('estado')->default(true); + $table->string('imagen'); + $table->timestamps(); + + // Definir correctamente la clave foránea + $table->foreign('categoria_id')->references('id')->on('categorias')->onDelete('cascade')->onUpdate('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Verificar si las tablas existen antes de eliminar las claves foráneas + if (Schema::hasTable('detalle_ventas')) { + Schema::table('detalle_ventas', function (Blueprint $table) { + $table->dropForeign(['producto_id']); + }); + } + + if (Schema::hasTable('detalle_compras')) { + Schema::table('detalle_compras', function (Blueprint $table) { + $table->dropForeign(['producto_id']); + }); + } + + Schema::dropIfExists('productos'); + } + + + +}; diff --git a/database/migrations/2025_03_29_002926_create_ventas_table.php b/database/migrations/2025_03_29_002926_create_ventas_table.php new file mode 100644 index 0000000..a93c8ba --- /dev/null +++ b/database/migrations/2025_03_29_002926_create_ventas_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('cliente_id')->nullable()->constrained(); + $table->decimal('total', 10, 2); + $table->enum('tipo_pago', ["Efectivo","Tarjeta","Transferencia"]); + $table->enum('estado', ["Pagado","Pendiente","Anulado"])->default('Pagado'); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('ventas'); + } +}; diff --git a/database/migrations/2025_03_29_002927_create_detalle_ventas_table.php b/database/migrations/2025_03_29_002927_create_detalle_ventas_table.php new file mode 100644 index 0000000..46476ee --- /dev/null +++ b/database/migrations/2025_03_29_002927_create_detalle_ventas_table.php @@ -0,0 +1,36 @@ +id(); + $table->foreignId('venta_id')->constrained(); + $table->foreignId('producto_id')->constrained(); + $table->integer('cantidad'); + $table->decimal('precio_unitario', 10, 2); + $table->decimal('subtotal', 10, 2); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('detalle_ventas'); + } +}; diff --git a/database/migrations/2025_03_29_002928_create_compras_table.php b/database/migrations/2025_03_29_002928_create_compras_table.php new file mode 100644 index 0000000..b188868 --- /dev/null +++ b/database/migrations/2025_03_29_002928_create_compras_table.php @@ -0,0 +1,34 @@ +id(); + $table->foreignId('proveedor_id')->nullable()->constrained('proveedors'); + $table->decimal('total', 10, 2); + $table->enum('estado', ["Recibida","Pendiente","Anulada"])->default('Recibida'); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('compras'); + } +}; diff --git a/database/migrations/2025_03_29_002929_create_detalle_compras_table.php b/database/migrations/2025_03_29_002929_create_detalle_compras_table.php new file mode 100644 index 0000000..592a023 --- /dev/null +++ b/database/migrations/2025_03_29_002929_create_detalle_compras_table.php @@ -0,0 +1,36 @@ +id(); + $table->foreignId('compra_id')->constrained(); + $table->foreignId('producto_id')->constrained(); + $table->integer('cantidad'); + $table->decimal('precio_unitario', 10, 2); + $table->decimal('subtotal', 10, 2); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('detalle_compras'); + } +}; diff --git a/database/migrations/2025_03_29_002931_create_cajas_table.php b/database/migrations/2025_03_29_002931_create_cajas_table.php new file mode 100644 index 0000000..3b6cca1 --- /dev/null +++ b/database/migrations/2025_03_29_002931_create_cajas_table.php @@ -0,0 +1,37 @@ +id(); + $table->decimal('monto_inicial', 10, 2); + $table->decimal('monto_final', 10, 2)->nullable(); + $table->timestamp('fecha_apertura')->useCurrent(); // Corrección aquí + $table->timestamp('fecha_cierre')->nullable(); + $table->enum('estado', ["Abierta", "Cerrada"])->default('Abierta'); + $table->timestamps(); + }); + + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cajas'); + } +}; diff --git a/database/migrations/2025_03_29_002932_create_movimiento_cajas_table.php b/database/migrations/2025_03_29_002932_create_movimiento_cajas_table.php new file mode 100644 index 0000000..ffa5357 --- /dev/null +++ b/database/migrations/2025_03_29_002932_create_movimiento_cajas_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('caja_id')->constrained(); + $table->enum('tipo', ["Ingreso","Egreso"]); + $table->decimal('monto', 10, 2); + $table->text('descripcion')->nullable(); + $table->timestamps(); + }); + + Schema::enableForeignKeyConstraints(); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('movimiento_cajas'); + } +}; diff --git a/database/migrations/2025_03_30_002003_create_colors_table.php b/database/migrations/2025_03_30_002003_create_colors_table.php new file mode 100644 index 0000000..6d3f13f --- /dev/null +++ b/database/migrations/2025_03_30_002003_create_colors_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('name', 50); + $table->string('hex_code', 7); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('colors'); + } +}; diff --git a/database/migrations/2025_03_30_002004_create_sizes_table.php b/database/migrations/2025_03_30_002004_create_sizes_table.php new file mode 100644 index 0000000..08126c6 --- /dev/null +++ b/database/migrations/2025_03_30_002004_create_sizes_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name', 10); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('sizes'); + } +}; diff --git a/database/migrations/2025_03_30_002006_create_product_variants_table.php b/database/migrations/2025_03_30_002006_create_product_variants_table.php new file mode 100644 index 0000000..d030e7e --- /dev/null +++ b/database/migrations/2025_03_30_002006_create_product_variants_table.php @@ -0,0 +1,33 @@ +id(); + $table->foreignId('producto_id')->constrained('productos')->onDelete('cascade')->onUpdate('cascade'); + $table->foreignId('color_id')->constrained('colors')->onDelete('cascade')->onUpdate('cascade'); + $table->foreignId('size_id')->constrained('sizes')->onDelete('cascade')->onUpdate('cascade'); + $table->integer('stock')->default(0); + $table->string('sku', 50)->unique(); + $table->string('barcode')->unique()->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('product_variants'); + } +}; diff --git a/database/migrations/2025_03_31_032648_create_permission_tables.php b/database/migrations/2025_03_31_032648_create_permission_tables.php new file mode 100644 index 0000000..70a120f --- /dev/null +++ b/database/migrations/2025_03_31_032648_create_permission_tables.php @@ -0,0 +1,140 @@ +engine('InnoDB'); + $table->bigIncrements('id'); // permission id + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + + $table->unique(['name', 'guard_name']); + }); + + Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) { + // $table->engine('InnoDB'); + $table->bigIncrements('id'); // role id + if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing + $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); + $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); + } + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + if ($teams || config('permission.testing')) { + $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); + } else { + $table->unique(['name', 'guard_name']); + } + }); + + Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) { + $table->unsignedBigInteger($pivotPermission); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } else { + $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } + + }); + + Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) { + $table->unsignedBigInteger($pivotRole); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } else { + $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } + }); + + Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) { + $table->unsignedBigInteger($pivotPermission); + $table->unsignedBigInteger($pivotRole); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + + $table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary'); + }); + + app('cache') + ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) + ->forget(config('permission.cache.key')); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $tableNames = config('permission.table_names'); + + if (empty($tableNames)) { + throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + } + + Schema::drop($tableNames['role_has_permissions']); + Schema::drop($tableNames['model_has_roles']); + Schema::drop($tableNames['model_has_permissions']); + Schema::drop($tableNames['roles']); + Schema::drop($tableNames['permissions']); + } +}; diff --git a/database/migrations/2025_04_28_220550_add_variante_id_to_detalle_ventas_table.php b/database/migrations/2025_04_28_220550_add_variante_id_to_detalle_ventas_table.php new file mode 100644 index 0000000..ce38fbe --- /dev/null +++ b/database/migrations/2025_04_28_220550_add_variante_id_to_detalle_ventas_table.php @@ -0,0 +1,28 @@ +unsignedBigInteger('variante_id')->nullable()->after('producto_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_ventas', function (Blueprint $table) { + $table->dropColumn('variante_id'); + }); + } +}; diff --git a/database/migrations/2025_05_02_233126_add_variante_id_to_detalle_compras_table.php b/database/migrations/2025_05_02_233126_add_variante_id_to_detalle_compras_table.php new file mode 100644 index 0000000..e361209 --- /dev/null +++ b/database/migrations/2025_05_02_233126_add_variante_id_to_detalle_compras_table.php @@ -0,0 +1,28 @@ +foreignId('variante_id')->nullable()->constrained('product_variants'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_compras', function (Blueprint $table) { + // + }); + } +}; diff --git a/database/migrations/2025_06_16_204436_add_stock_minimo_to_productos_table.php b/database/migrations/2025_06_16_204436_add_stock_minimo_to_productos_table.php new file mode 100644 index 0000000..1947bad --- /dev/null +++ b/database/migrations/2025_06_16_204436_add_stock_minimo_to_productos_table.php @@ -0,0 +1,28 @@ +integer('stock_minimo')->default(0)->after('stock'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('productos', function (Blueprint $table) { + $table->dropColumn('stock_minimo'); + }); + } +}; diff --git a/database/migrations/2025_09_30_205831_add_stock_maximo_to_productos_table.php b/database/migrations/2025_09_30_205831_add_stock_maximo_to_productos_table.php new file mode 100644 index 0000000..e079624 --- /dev/null +++ b/database/migrations/2025_09_30_205831_add_stock_maximo_to_productos_table.php @@ -0,0 +1,28 @@ +integer('stock_maximo')->default(1000)->after('stock_minimo'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('productos', function (Blueprint $table) { + $table->dropColumn('stock_maximo'); + }); + } +}; diff --git a/database/migrations/2025_10_14_000000_add_unidad_medida_to_productos_table.php b/database/migrations/2025_10_14_000000_add_unidad_medida_to_productos_table.php new file mode 100644 index 0000000..ba01411 --- /dev/null +++ b/database/migrations/2025_10_14_000000_add_unidad_medida_to_productos_table.php @@ -0,0 +1,28 @@ +string('unidad_medida')->default('unidad')->after('stock_maximo'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('productos', function (Blueprint $table) { + $table->dropColumn('unidad_medida'); + }); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_10_14_000001_create_bodegas_table.php b/database/migrations/2025_10_14_000001_create_bodegas_table.php new file mode 100644 index 0000000..e0e4096 --- /dev/null +++ b/database/migrations/2025_10_14_000001_create_bodegas_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('nombre', 100)->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('bodegas'); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_10_14_000002_create_producto_bodega_table.php b/database/migrations/2025_10_14_000002_create_producto_bodega_table.php new file mode 100644 index 0000000..e28fd04 --- /dev/null +++ b/database/migrations/2025_10_14_000002_create_producto_bodega_table.php @@ -0,0 +1,37 @@ +id(); + $table->foreignId('producto_id')->constrained('productos')->onDelete('cascade'); + $table->foreignId('bodega_id')->constrained('bodegas')->onDelete('cascade'); + $table->integer('stock')->default(0); + $table->timestamps(); + + // Índice único para evitar duplicados + $table->unique(['producto_id', 'bodega_id']); + + // Índices para optimizar consultas + $table->index(['producto_id', 'stock']); + $table->index(['bodega_id', 'stock']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('producto_bodega'); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_10_14_000003_create_transferencias_bodega_table.php b/database/migrations/2025_10_14_000003_create_transferencias_bodega_table.php new file mode 100644 index 0000000..afa94b7 --- /dev/null +++ b/database/migrations/2025_10_14_000003_create_transferencias_bodega_table.php @@ -0,0 +1,39 @@ +id(); + $table->foreignId('producto_id')->constrained('productos')->onDelete('cascade'); + $table->foreignId('bodega_origen_id')->constrained('bodegas')->onDelete('cascade'); + $table->foreignId('bodega_destino_id')->constrained('bodegas')->onDelete('cascade'); + $table->integer('cantidad'); + $table->text('motivo')->nullable(); + $table->foreignId('usuario_id')->constrained('users')->onDelete('cascade'); + $table->timestamp('fecha_transferencia'); + $table->timestamps(); + + // Índices para optimizar consultas + $table->index(['producto_id', 'fecha_transferencia']); + $table->index(['bodega_origen_id', 'fecha_transferencia']); + $table->index(['bodega_destino_id', 'fecha_transferencia']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('transferencias_bodega'); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_10_14_000004_create_variante_bodega_table.php b/database/migrations/2025_10_14_000004_create_variante_bodega_table.php new file mode 100644 index 0000000..d652f90 --- /dev/null +++ b/database/migrations/2025_10_14_000004_create_variante_bodega_table.php @@ -0,0 +1,37 @@ +id(); + $table->foreignId('variante_id')->constrained('product_variants')->onDelete('cascade'); + $table->foreignId('bodega_id')->constrained('bodegas')->onDelete('cascade'); + $table->integer('stock')->default(0); + $table->timestamps(); + + // Índice único para evitar duplicados + $table->unique(['variante_id', 'bodega_id']); + + // Índices para optimizar consultas + $table->index(['variante_id', 'stock']); + $table->index(['bodega_id', 'stock']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('variante_bodega'); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_10_17_222709_add_variante_id_to_transferencias_bodega_table.php b/database/migrations/2025_10_17_222709_add_variante_id_to_transferencias_bodega_table.php new file mode 100644 index 0000000..582d6c5 --- /dev/null +++ b/database/migrations/2025_10_17_222709_add_variante_id_to_transferencias_bodega_table.php @@ -0,0 +1,37 @@ +foreignId('variante_id') + ->nullable() + ->after('producto_id') + ->constrained('product_variants') + ->onDelete('cascade'); + + // Índice para optimizar consultas por variante + $table->index(['variante_id', 'fecha_transferencia']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('transferencias_bodega', function (Blueprint $table) { + $table->dropForeign(['variante_id']); + $table->dropIndex(['variante_id', 'fecha_transferencia']); + $table->dropColumn('variante_id'); + }); + } +}; diff --git a/database/migrations/2025_10_17_234351_make_descripcion_nullable_in_productos_table.php b/database/migrations/2025_10_17_234351_make_descripcion_nullable_in_productos_table.php new file mode 100644 index 0000000..f2f6c57 --- /dev/null +++ b/database/migrations/2025_10_17_234351_make_descripcion_nullable_in_productos_table.php @@ -0,0 +1,28 @@ +text('descripcion')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('productos', function (Blueprint $table) { + $table->text('descripcion')->nullable(false)->change(); + }); + } +}; diff --git a/database/migrations/2025_10_18_011026_limpiar_stock_productos_con_variantes.php b/database/migrations/2025_10_18_011026_limpiar_stock_productos_con_variantes.php new file mode 100644 index 0000000..30077d7 --- /dev/null +++ b/database/migrations/2025_10_18_011026_limpiar_stock_productos_con_variantes.php @@ -0,0 +1,52 @@ +where('stock', '>', 0) + ->whereExists(function ($query) { + $query->select(DB::raw(1)) + ->from('product_variants') + ->whereColumn('product_variants.producto_id', 'productos.id'); + }) + ->get(); + + Log::info("Encontrados " . $productosConVariantes->count() . " productos con stock directo y variantes"); + + foreach ($productosConVariantes as $producto) { + $stockAnterior = $producto->stock; + + // Limpiar el stock del producto principal + DB::table('productos') + ->where('id', $producto->id) + ->update(['stock' => 0]); + + Log::info("Stock limpiado para producto ID {$producto->id}: {$stockAnterior} → 0"); + } + + Log::info("Limpieza de stock completada exitosamente"); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // No se puede deshacer esta migración porque no sabemos cuál era el stock original + Log::info("Esta migración no se puede deshacer - el stock anterior no se puede recuperar"); + } +}; diff --git a/database/migrations/2025_10_18_011718_add_bodega_id_to_detalle_compras_table.php b/database/migrations/2025_10_18_011718_add_bodega_id_to_detalle_compras_table.php new file mode 100644 index 0000000..7a1ba9b --- /dev/null +++ b/database/migrations/2025_10_18_011718_add_bodega_id_to_detalle_compras_table.php @@ -0,0 +1,29 @@ +foreignId('bodega_id')->nullable()->constrained('bodegas')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_compras', function (Blueprint $table) { + $table->dropForeign(['bodega_id']); + $table->dropColumn('bodega_id'); + }); + } +}; diff --git a/database/migrations/2025_10_18_012158_set_default_bodega_in_existing_detalle_compras.php b/database/migrations/2025_10_18_012158_set_default_bodega_in_existing_detalle_compras.php new file mode 100644 index 0000000..b9429cc --- /dev/null +++ b/database/migrations/2025_10_18_012158_set_default_bodega_in_existing_detalle_compras.php @@ -0,0 +1,59 @@ +where('nombre', 'Principal') + ->first(); + + if (!$bodegaPrincipal) { + $bodegaPrincipalId = DB::table('bodegas')->insertGetId([ + 'nombre' => 'Principal', + 'created_at' => now(), + 'updated_at' => now(), + ]); + Log::info("Bodega Principal creada con ID: {$bodegaPrincipalId}"); + } else { + $bodegaPrincipalId = $bodegaPrincipal->id; + Log::info("Bodega Principal encontrada con ID: {$bodegaPrincipalId}"); + } + + // Actualizar detalles de compra sin bodega asignada + $detallesSinBodega = DB::table('detalle_compras') + ->whereNull('bodega_id') + ->update(['bodega_id' => $bodegaPrincipalId]); + + Log::info("Actualizados {$detallesSinBodega} detalles de compra con bodega Principal"); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Opcional: remover las asignaciones de bodega + DB::table('detalle_compras') + ->where('bodega_id', function ($query) { + $query->select('id') + ->from('bodegas') + ->where('nombre', 'Principal'); + }) + ->update(['bodega_id' => null]); + + Log::info("Eliminadas asignaciones de bodega Principal en detalles de compra"); + } +}; diff --git a/database/migrations/2025_10_18_143254_update_foreign_keys_detalle_compras_table.php b/database/migrations/2025_10_18_143254_update_foreign_keys_detalle_compras_table.php new file mode 100644 index 0000000..8839060 --- /dev/null +++ b/database/migrations/2025_10_18_143254_update_foreign_keys_detalle_compras_table.php @@ -0,0 +1,133 @@ +string('producto_nombre_snapshot')->nullable()->after('producto_id'); + $table->string('variante_info_snapshot')->nullable()->after('variante_id'); + }); + + // Paso 2: Actualizar registros existentes con snapshot de información + try { + DB::unprepared(" + UPDATE detalle_compras + SET producto_nombre_snapshot = productos.nombre + FROM productos + WHERE productos.id = detalle_compras.producto_id + AND detalle_compras.producto_id IS NOT NULL + AND detalle_compras.producto_nombre_snapshot IS NULL + "); + } catch (\Exception $e) { + // Si falla, intentar con la sintaxis estándar + \Illuminate\Support\Facades\DB::table('detalle_compras') + ->whereNotNull('producto_id') + ->whereNull('producto_nombre_snapshot') + ->get() + ->each(function ($detalle) { + $producto = \Illuminate\Support\Facades\DB::table('productos') + ->where('id', $detalle->producto_id) + ->first(); + if ($producto) { + \Illuminate\Support\Facades\DB::table('detalle_compras') + ->where('id', $detalle->id) + ->update(['producto_nombre_snapshot' => $producto->nombre]); + } + }); + } + + try { + DB::unprepared(" + UPDATE detalle_compras + SET variante_info_snapshot = CONCAT(c.name, ' / ', s.name) + FROM product_variants pv + JOIN colors c ON c.id = pv.color_id + JOIN sizes s ON s.id = pv.size_id + WHERE pv.id = detalle_compras.variante_id + AND detalle_compras.variante_id IS NOT NULL + AND detalle_compras.variante_info_snapshot IS NULL + "); + } catch (\Exception $e) { + // Si falla, intentar con la sintaxis estándar + \Illuminate\Support\Facades\DB::table('detalle_compras') + ->whereNotNull('variante_id') + ->whereNull('variante_info_snapshot') + ->get() + ->each(function ($detalle) { + $variante = \Illuminate\Support\Facades\DB::table('product_variants as pv') + ->join('colors as c', 'c.id', '=', 'pv.color_id') + ->join('sizes as s', 's.id', '=', 'pv.size_id') + ->where('pv.id', $detalle->variante_id) + ->select(\Illuminate\Support\Facades\DB::raw("CONCAT(c.name, ' / ', s.name) as info")) + ->first(); + if ($variante) { + \Illuminate\Support\Facades\DB::table('detalle_compras') + ->where('id', $detalle->id) + ->update(['variante_info_snapshot' => $variante->info]); + } + }); + } + + // Paso 3: Actualizar claves foráneas + Schema::table('detalle_compras', function (Blueprint $table) { + // Eliminar las claves foráneas existentes si existen + try { + $table->dropForeign(['producto_id']); + } catch (\Exception $e) { + // La clave foránea puede no existir + } + + try { + $table->dropForeign(['variante_id']); + } catch (\Exception $e) { + // La clave foránea puede no existir + } + + // Recrear las claves foráneas con SET NULL para preservar historial + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('set null'); + + $table->foreign('variante_id') + ->references('id') + ->on('product_variants') + ->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_compras', function (Blueprint $table) { + // Revertir a las claves foráneas originales + $table->dropForeign(['producto_id']); + $table->dropForeign(['variante_id']); + + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('restrict'); // Comportamiento original + + $table->foreign('variante_id') + ->references('id') + ->on('product_variants') + ->onDelete('restrict'); // Comportamiento original + + // Eliminar los campos snapshot + $table->dropColumn(['producto_nombre_snapshot', 'variante_info_snapshot']); + }); + } +}; diff --git a/database/migrations/2025_10_18_144027_make_producto_id_nullable_in_detalle_compras.php b/database/migrations/2025_10_18_144027_make_producto_id_nullable_in_detalle_compras.php new file mode 100644 index 0000000..2d8b8f9 --- /dev/null +++ b/database/migrations/2025_10_18_144027_make_producto_id_nullable_in_detalle_compras.php @@ -0,0 +1,30 @@ +unsignedBigInteger('producto_id')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_compras', function (Blueprint $table) { + // Revertir a NOT NULL (solo si no hay registros con NULL) + $table->unsignedBigInteger('producto_id')->nullable(false)->change(); + }); + } +}; diff --git a/database/migrations/2025_10_18_144114_make_variante_id_nullable_in_detalle_compras.php b/database/migrations/2025_10_18_144114_make_variante_id_nullable_in_detalle_compras.php new file mode 100644 index 0000000..326be71 --- /dev/null +++ b/database/migrations/2025_10_18_144114_make_variante_id_nullable_in_detalle_compras.php @@ -0,0 +1,30 @@ +unsignedBigInteger('variante_id')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_compras', function (Blueprint $table) { + // Revertir a NOT NULL (solo si no hay registros con NULL) + $table->unsignedBigInteger('variante_id')->nullable(false)->change(); + }); + } +}; diff --git a/database/migrations/2025_10_18_144818_make_producto_variante_id_nullable_in_detalle_ventas.php b/database/migrations/2025_10_18_144818_make_producto_variante_id_nullable_in_detalle_ventas.php new file mode 100644 index 0000000..5aa7d5a --- /dev/null +++ b/database/migrations/2025_10_18_144818_make_producto_variante_id_nullable_in_detalle_ventas.php @@ -0,0 +1,137 @@ +string('producto_nombre_snapshot')->nullable()->after('producto_id'); + $table->string('variante_info_snapshot')->nullable()->after('variante_id'); + }); + + // Paso 2: Actualizar registros existentes con snapshot de información + // Usar DB::unprepared para evitar problemas de transacción en PostgreSQL + try { + DB::unprepared(" + UPDATE detalle_ventas + SET producto_nombre_snapshot = productos.nombre + FROM productos + WHERE productos.id = detalle_ventas.producto_id + AND detalle_ventas.producto_id IS NOT NULL + AND detalle_ventas.producto_nombre_snapshot IS NULL + "); + } catch (\Exception $e) { + // Si falla, intentar con la sintaxis estándar + \Illuminate\Support\Facades\DB::table('detalle_ventas') + ->whereNotNull('producto_id') + ->whereNull('producto_nombre_snapshot') + ->get() + ->each(function ($detalle) { + $producto = \Illuminate\Support\Facades\DB::table('productos') + ->where('id', $detalle->producto_id) + ->first(); + if ($producto) { + \Illuminate\Support\Facades\DB::table('detalle_ventas') + ->where('id', $detalle->id) + ->update(['producto_nombre_snapshot' => $producto->nombre]); + } + }); + } + + try { + DB::unprepared(" + UPDATE detalle_ventas + SET variante_info_snapshot = CONCAT(c.name, ' / ', s.name) + FROM product_variants pv + JOIN colors c ON c.id = pv.color_id + JOIN sizes s ON s.id = pv.size_id + WHERE pv.id = detalle_ventas.variante_id + AND detalle_ventas.variante_id IS NOT NULL + AND detalle_ventas.variante_info_snapshot IS NULL + "); + } catch (\Exception $e) { + // Si falla, intentar con la sintaxis estándar + \Illuminate\Support\Facades\DB::table('detalle_ventas') + ->whereNotNull('variante_id') + ->whereNull('variante_info_snapshot') + ->get() + ->each(function ($detalle) { + $variante = \Illuminate\Support\Facades\DB::table('product_variants as pv') + ->join('colors as c', 'c.id', '=', 'pv.color_id') + ->join('sizes as s', 's.id', '=', 'pv.size_id') + ->where('pv.id', $detalle->variante_id) + ->select(\Illuminate\Support\Facades\DB::raw("CONCAT(c.name, ' / ', s.name) as info")) + ->first(); + if ($variante) { + \Illuminate\Support\Facades\DB::table('detalle_ventas') + ->where('id', $detalle->id) + ->update(['variante_info_snapshot' => $variante->info]); + } + }); + } + + // Paso 3: Hacer nullable las columnas producto_id y variante_id + Schema::table('detalle_ventas', function (Blueprint $table) { + $table->unsignedBigInteger('producto_id')->nullable()->change(); + $table->unsignedBigInteger('variante_id')->nullable()->change(); + }); + + // Paso 4: Actualizar claves foráneas para usar SET NULL + try { + Schema::table('detalle_ventas', function (Blueprint $table) { + $table->dropForeign(['producto_id']); + $table->dropForeign(['variante_id']); + + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('set null'); + + $table->foreign('variante_id') + ->references('id') + ->on('product_variants') + ->onDelete('set null'); + }); + } catch (\Exception $e) { + // Las claves foráneas pueden no existir + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_ventas', function (Blueprint $table) { + // Revertir claves foráneas + $table->dropForeign(['producto_id']); + $table->dropForeign(['variante_id']); + + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('restrict'); + + $table->foreign('variante_id') + ->references('id') + ->on('product_variants') + ->onDelete('restrict'); + + // Revertir a NOT NULL (solo si no hay registros con NULL) + $table->unsignedBigInteger('producto_id')->nullable(false)->change(); + $table->unsignedBigInteger('variante_id')->nullable(false)->change(); + + // Eliminar campos snapshot + $table->dropColumn(['producto_nombre_snapshot', 'variante_info_snapshot']); + }); + } +}; diff --git a/database/migrations/2025_10_18_150835_update_detalle_ventas_foreign_keys.php b/database/migrations/2025_10_18_150835_update_detalle_ventas_foreign_keys.php new file mode 100644 index 0000000..5896cd7 --- /dev/null +++ b/database/migrations/2025_10_18_150835_update_detalle_ventas_foreign_keys.php @@ -0,0 +1,52 @@ +unsignedBigInteger('producto_id')->nullable()->change(); + }); + + // Actualizar claves foráneas para usar SET NULL + try { + Schema::table('detalle_ventas', function (Blueprint $table) { + $table->dropForeign(['producto_id']); + + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('set null'); + }); + } catch (\Exception $e) { + // La clave foránea puede no existir + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_ventas', function (Blueprint $table) { + try { + $table->dropForeign(['producto_id']); + + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('restrict'); + } catch (\Exception $e) { + // La clave foránea puede no existir + } + }); + } +}; diff --git a/database/migrations/2025_10_21_000151_add_bodega_id_to_detalle_ventas_table.php b/database/migrations/2025_10_21_000151_add_bodega_id_to_detalle_ventas_table.php new file mode 100644 index 0000000..6f652dd --- /dev/null +++ b/database/migrations/2025_10_21_000151_add_bodega_id_to_detalle_ventas_table.php @@ -0,0 +1,30 @@ +foreignId('bodega_id')->nullable()->constrained('bodegas')->onDelete('set null'); + $table->index('bodega_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_ventas', function (Blueprint $table) { + $table->dropForeign(['bodega_id']); + $table->dropColumn('bodega_id'); + }); + } +}; diff --git a/database/migrations/2025_10_21_194714_update_detalle_ventas_producto_id_foreign_key.php b/database/migrations/2025_10_21_194714_update_detalle_ventas_producto_id_foreign_key.php new file mode 100644 index 0000000..714031a --- /dev/null +++ b/database/migrations/2025_10_21_194714_update_detalle_ventas_producto_id_foreign_key.php @@ -0,0 +1,64 @@ +unsignedBigInteger('producto_id')->nullable()->change(); + + // Eliminar la clave foránea existente usando el nombre exacto + $table->dropForeign('detalle_ventas_producto_id_foreign'); + + // Recrear la clave foránea con SET NULL + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('set null'); + }); + + // También crear clave foránea para variante_id (no existe actualmente según la consulta) + if (Schema::hasColumn('detalle_ventas', 'variante_id')) { + Schema::table('detalle_ventas', function (Blueprint $table) { + // variante_id ya es nullable + + // Crear la clave foránea con SET NULL (no existe actualmente) + $table->foreign('variante_id') + ->references('id') + ->on('product_variants') + ->onDelete('set null'); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_ventas', function (Blueprint $table) { + // Revertir las claves foráneas a RESTRICT + $table->dropForeign(['producto_id']); + $table->foreign('producto_id') + ->references('id') + ->on('productos') + ->onDelete('restrict'); + + if (Schema::hasColumn('detalle_ventas', 'variante_id')) { + $table->dropForeign(['variante_id']); + // No recrear variante_id foreign key en down ya que no existía originalmente + } + + // Revertir producto_id a NOT NULL + $table->unsignedBigInteger('producto_id')->nullable(false)->change(); + }); + } +}; diff --git a/database/migrations/2025_11_21_203721_add_precio_modificado_fields_to_detalle_ventas_table.php b/database/migrations/2025_11_21_203721_add_precio_modificado_fields_to_detalle_ventas_table.php new file mode 100644 index 0000000..77f716a --- /dev/null +++ b/database/migrations/2025_11_21_203721_add_precio_modificado_fields_to_detalle_ventas_table.php @@ -0,0 +1,31 @@ +decimal('precio_original', 10, 2)->nullable()->after('precio_unitario'); + $table->decimal('descuento_aplicado', 10, 2)->default(0)->after('precio_original'); + $table->foreignId('usuario_modifico_precio_id')->nullable()->constrained('users')->after('descuento_aplicado'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_ventas', function (Blueprint $table) { + $table->dropForeign(['usuario_modifico_precio_id']); + $table->dropColumn(['precio_original', 'descuento_aplicado', 'usuario_modifico_precio_id']); + }); + } +}; diff --git a/database/migrations/2025_11_21_215929_add_cascade_delete_to_detalle_ventas_venta_id.php b/database/migrations/2025_11_21_215929_add_cascade_delete_to_detalle_ventas_venta_id.php new file mode 100644 index 0000000..83ba699 --- /dev/null +++ b/database/migrations/2025_11_21_215929_add_cascade_delete_to_detalle_ventas_venta_id.php @@ -0,0 +1,41 @@ +dropForeign(['venta_id']); + + // Recrear la foreign key con onDelete cascade + $table->foreign('venta_id') + ->references('id') + ->on('ventas') + ->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_ventas', function (Blueprint $table) { + // Eliminar la foreign key con cascade + $table->dropForeign(['venta_id']); + + // Recrear la foreign key sin cascade (estado original) + $table->foreign('venta_id') + ->references('id') + ->on('ventas'); + }); + } +}; diff --git a/database/migrations/2025_12_02_190924_add_detalle_compra_column_to_detalle_compras_table.php b/database/migrations/2025_12_02_190924_add_detalle_compra_column_to_detalle_compras_table.php new file mode 100644 index 0000000..22d7920 --- /dev/null +++ b/database/migrations/2025_12_02_190924_add_detalle_compra_column_to_detalle_compras_table.php @@ -0,0 +1,28 @@ +string('DetalleCompra', 255)->nullable()->after('subtotal'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('detalle_compras', function (Blueprint $table) { + $table->dropColumn('DetalleCompra'); + }); + } +}; diff --git a/database/seeders/CrudPermissionSeeder.php b/database/seeders/CrudPermissionSeeder.php new file mode 100644 index 0000000..71a8f2b --- /dev/null +++ b/database/seeders/CrudPermissionSeeder.php @@ -0,0 +1,44 @@ + $permission, 'guard_name' => 'web']); + } + + // Crear roles + $adminRole = Role::firstOrCreate(['name' => 'Administrador']); + $userRole = Role::firstOrCreate(['name' => 'Usuario']); + + // Asignar permisos a roles + $adminRole->givePermissionTo($permissions); // Admin puede ver todo + $userRole->givePermissionTo([ + 'ver inventario', + 'ver colores', + 'ver productos', + 'ver sizes', + 'ver variantes de productos', + ]); // Usuario solo puede ver Inventario + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php new file mode 100644 index 0000000..d01a0ef --- /dev/null +++ b/database/seeders/DatabaseSeeder.php @@ -0,0 +1,23 @@ +create(); + + User::factory()->create([ + 'name' => 'Test User', + 'email' => 'test@example.com', + ]); + } +} diff --git a/draft.yaml b/draft.yaml new file mode 100644 index 0000000..c040443 --- /dev/null +++ b/draft.yaml @@ -0,0 +1,114 @@ +models: + Producto: + nombre: string:255 + descripcion: text nullable + codigo_barras: string:50 unique + precio_compra: decimal:10,2 + precio_venta: decimal:10,2 + stock: integer + categoria_id: id foreign:categorias + estado: enum:activo,inactivo default:activo + + Categoria: + nombre: string:255 + descripcion: text nullable + + Cliente: + nombre: string:255 + correo: string:255 unique nullable + telefono: string:20 nullable + direccion: text nullable + tipo_documento: enum:DNI,RUC,PASAPORTE + numero_documento: string:20 unique + + Proveedor: + nombre: string:255 + contacto: string:255 nullable + telefono: string:20 nullable + correo: string:255 unique nullable + direccion: text nullable + + Venta: + fecha: timestamp default:CURRENT_TIMESTAMP + cliente_id: id foreign:clientes nullable + total: decimal:10,2 + tipo_pago: enum:Efectivo,Tarjeta,Transferencia + estado: enum:Pagado,Pendiente,Anulado default:Pagado + + DetalleVenta: + venta_id: id foreign:ventas + producto_id: id foreign:productos + cantidad: integer + precio_unitario: decimal:10,2 + subtotal: decimal:10,2 + + Compra: + fecha: timestamp default:CURRENT_TIMESTAMP + proveedor_id: id foreign:proveedores nullable + total: decimal:10,2 + estado: enum:Recibida,Pendiente,Anulada default:Recibida + + DetalleCompra: + compra_id: id foreign:compras + producto_id: id foreign:productos + cantidad: integer + precio_unitario: decimal:10,2 + subtotal: decimal:10,2 + + Inventario: + producto_id: id foreign:productos + stock_actual: integer + stock_minimo: integer + ubicacion: string:255 nullable + + Caja: + monto_inicial: decimal:10,2 + monto_final: decimal:10,2 nullable + fecha_apertura: datetime default:CURRENT_TIMESTAMP + fecha_cierre: datetime nullable + estado: enum:Abierta,Cerrada default:Abierta + + MovimientoCaja: + caja_id: id foreign:cajas + tipo: enum:Ingreso,Egreso + monto: decimal:10,2 + descripcion: text nullable + fecha: datetime default:CURRENT_TIMESTAMP + +controllers: + Producto: + resource: api + Categoria: + resource: api + Cliente: + resource: api + Proveedor: + resource: api + Venta: + resource: api + DetalleVenta: + resource: api + Compra: + resource: api + DetalleCompra: + resource: api + Inventario: + resource: api + Caja: + resource: api + MovimientoCaja: + resource: api + +filament: + resources: + Producto: all + Categoria: all + Cliente: all + Proveedor: all + Venta: all + DetalleVenta: all + Compra: all + DetalleCompra: all + Inventario: all + Caja: all + MovimientoCaja: all diff --git a/lang/vendor/filament/ar/components/button.php b/lang/vendor/filament/ar/components/button.php new file mode 100644 index 0000000..96d6aa0 --- /dev/null +++ b/lang/vendor/filament/ar/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'جاري رفع الملف...', + ], + +]; diff --git a/lang/vendor/filament/ar/components/copyable.php b/lang/vendor/filament/ar/components/copyable.php new file mode 100644 index 0000000..b9b2e69 --- /dev/null +++ b/lang/vendor/filament/ar/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'تم النسخ', + ], + +]; diff --git a/lang/vendor/filament/ar/components/modal.php b/lang/vendor/filament/ar/components/modal.php new file mode 100644 index 0000000..9bd2463 --- /dev/null +++ b/lang/vendor/filament/ar/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'إغلاق', + ], + + ], + +]; diff --git a/lang/vendor/filament/ar/components/pagination.php b/lang/vendor/filament/ar/components/pagination.php new file mode 100644 index 0000000..427af1a --- /dev/null +++ b/lang/vendor/filament/ar/components/pagination.php @@ -0,0 +1,47 @@ + 'التنقل بين الصفحات', + + 'overview' => '{1} عرض نتيجة واحدة|[3,10] عرض :first إلى :last من :total نتائج|[2,*] عرض :first إلى :last من :total نتيجة', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'لكل صفحة', + + 'options' => [ + 'all' => 'الكل', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'الأولي', + ], + + 'go_to_page' => [ + 'label' => 'انتقل إلى صفحة :page', + ], + + 'last' => [ + 'label' => 'الأخيرة', + ], + + 'next' => [ + 'label' => 'التالي', + ], + + 'previous' => [ + 'label' => 'السابق', + ], + + ], + +]; diff --git a/lang/vendor/filament/az/components/button.php b/lang/vendor/filament/az/components/button.php new file mode 100644 index 0000000..878f74c --- /dev/null +++ b/lang/vendor/filament/az/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Fayl yüklənir...', + ], + +]; diff --git a/lang/vendor/filament/az/components/copyable.php b/lang/vendor/filament/az/components/copyable.php new file mode 100644 index 0000000..4b0c3ea --- /dev/null +++ b/lang/vendor/filament/az/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopyalandı', + ], + +]; diff --git a/lang/vendor/filament/az/components/modal.php b/lang/vendor/filament/az/components/modal.php new file mode 100644 index 0000000..c515b80 --- /dev/null +++ b/lang/vendor/filament/az/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Bağla', + ], + + ], + +]; diff --git a/lang/vendor/filament/az/components/pagination.php b/lang/vendor/filament/az/components/pagination.php new file mode 100644 index 0000000..72a7f81 --- /dev/null +++ b/lang/vendor/filament/az/components/pagination.php @@ -0,0 +1,45 @@ + 'Səhifələndirmə Naviqasiyası', + + 'overview' => 'Toplam :total nəticədən :first ile :last arası göstərilir', + + 'fields' => [ + + 'records_per_page' => [ + 'label' => 'səhifə başına', + + 'options' => [ + 'all' => 'Hamısı', + ], + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Birinci', + ], + + 'go_to_page' => [ + 'label' => ':page. səhifəyə get', + ], + + 'next' => [ + 'label' => 'Sonrakı', + ], + + 'last' => [ + 'label' => 'Son', + ], + + 'previous' => [ + 'label' => 'Əvvəlki', + ], + + ], + +]; diff --git a/lang/vendor/filament/bg/components/button.php b/lang/vendor/filament/bg/components/button.php new file mode 100644 index 0000000..a732754 --- /dev/null +++ b/lang/vendor/filament/bg/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Качване на файл...', + ], + +]; diff --git a/lang/vendor/filament/bg/components/copyable.php b/lang/vendor/filament/bg/components/copyable.php new file mode 100644 index 0000000..7753fd7 --- /dev/null +++ b/lang/vendor/filament/bg/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Копирано', + ], + +]; diff --git a/lang/vendor/filament/bg/components/modal.php b/lang/vendor/filament/bg/components/modal.php new file mode 100644 index 0000000..8ca951f --- /dev/null +++ b/lang/vendor/filament/bg/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Затвори', + ], + + ], + +]; diff --git a/lang/vendor/filament/bg/components/pagination.php b/lang/vendor/filament/bg/components/pagination.php new file mode 100644 index 0000000..7a2df50 --- /dev/null +++ b/lang/vendor/filament/bg/components/pagination.php @@ -0,0 +1,47 @@ + 'Наигация на странициране', + + 'overview' => '{1} Показване на 1 резултат|[2,*] Показване на :first до :last от общо :total резултата', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Резултати на страница', + + 'options' => [ + 'all' => 'Всички', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Първа', + ], + + 'go_to_page' => [ + 'label' => 'Отиди на страница :page', + ], + + 'last' => [ + 'label' => 'Последна', + ], + + 'next' => [ + 'label' => 'Следваща', + ], + + 'previous' => [ + 'label' => 'Предишна', + ], + + ], + +]; diff --git a/lang/vendor/filament/bn/components/button.php b/lang/vendor/filament/bn/components/button.php new file mode 100644 index 0000000..6869f2f --- /dev/null +++ b/lang/vendor/filament/bn/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'নথি আপলোড হচ্ছে...', + ], + +]; diff --git a/lang/vendor/filament/bn/components/copyable.php b/lang/vendor/filament/bn/components/copyable.php new file mode 100644 index 0000000..4cf5ce9 --- /dev/null +++ b/lang/vendor/filament/bn/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'অনুকৃত', + ], + +]; diff --git a/lang/vendor/filament/bn/components/modal.php b/lang/vendor/filament/bn/components/modal.php new file mode 100644 index 0000000..2471549 --- /dev/null +++ b/lang/vendor/filament/bn/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'বন্ধ করুন', + ], + + ], + +]; diff --git a/lang/vendor/filament/bn/components/pagination.php b/lang/vendor/filament/bn/components/pagination.php new file mode 100644 index 0000000..658decc --- /dev/null +++ b/lang/vendor/filament/bn/components/pagination.php @@ -0,0 +1,39 @@ + 'পৃষ্ঠা সংখ্যাগুলো', + + 'overview' => ':total এর, :first থেকে :last পর্যন্ত দেখানো হচ্ছে', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'প্রতি পৃষ্ঠা', + + 'options' => [ + 'all' => 'সব', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => ':page পৃষ্টায় যান', + ], + + 'next' => [ + 'label' => 'পরবর্তী', + ], + + 'previous' => [ + 'label' => 'পূর্ববর্তী', + ], + + ], + +]; diff --git a/lang/vendor/filament/bs/components/button.php b/lang/vendor/filament/bs/components/button.php new file mode 100644 index 0000000..2d28427 --- /dev/null +++ b/lang/vendor/filament/bs/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Učitavanje fajlova...', + ], + +]; diff --git a/lang/vendor/filament/bs/components/copyable.php b/lang/vendor/filament/bs/components/copyable.php new file mode 100644 index 0000000..0741c30 --- /dev/null +++ b/lang/vendor/filament/bs/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopirano', + ], + +]; diff --git a/lang/vendor/filament/bs/components/modal.php b/lang/vendor/filament/bs/components/modal.php new file mode 100644 index 0000000..99e56d0 --- /dev/null +++ b/lang/vendor/filament/bs/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Zatvoriti', + ], + + ], + +]; diff --git a/lang/vendor/filament/bs/components/pagination.php b/lang/vendor/filament/bs/components/pagination.php new file mode 100644 index 0000000..a70f29e --- /dev/null +++ b/lang/vendor/filament/bs/components/pagination.php @@ -0,0 +1,39 @@ + 'Navigacija po stranicama', + + 'overview' => '{1} Prikazuje 1 rezultat|[2,*]Prikazivanje :first od :last od ukupno :total rezultata', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'po stranici', + + 'options' => [ + 'all' => 'Svi', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Idite na stranicu :page', + ], + + 'next' => [ + 'label' => 'Dalje', + ], + + 'previous' => [ + 'label' => 'Nazad', + ], + + ], + +]; diff --git a/lang/vendor/filament/ca/components/button.php b/lang/vendor/filament/ca/components/button.php new file mode 100644 index 0000000..a7e0eb5 --- /dev/null +++ b/lang/vendor/filament/ca/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Pujant arxiu...', + ], + +]; diff --git a/lang/vendor/filament/ca/components/copyable.php b/lang/vendor/filament/ca/components/copyable.php new file mode 100644 index 0000000..4311f32 --- /dev/null +++ b/lang/vendor/filament/ca/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copiat', + ], + +]; diff --git a/lang/vendor/filament/ca/components/modal.php b/lang/vendor/filament/ca/components/modal.php new file mode 100644 index 0000000..8edca02 --- /dev/null +++ b/lang/vendor/filament/ca/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Tancar', + ], + + ], + +]; diff --git a/lang/vendor/filament/ca/components/pagination.php b/lang/vendor/filament/ca/components/pagination.php new file mode 100644 index 0000000..5778231 --- /dev/null +++ b/lang/vendor/filament/ca/components/pagination.php @@ -0,0 +1,47 @@ + 'Paginació', + + 'overview' => '{1} Mostrant 1 resultat|[2,*] Mostrant :first a :last de :total resultats', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Per pàgina', + + 'options' => [ + 'all' => 'Tots', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Primera', + ], + + 'go_to_page' => [ + 'label' => 'Anar a la pàgina :page', + ], + + 'last' => [ + 'label' => 'Última', + ], + + 'next' => [ + 'label' => 'Següent', + ], + + 'previous' => [ + 'label' => 'Anterior', + ], + + ], + +]; diff --git a/lang/vendor/filament/ckb/components/button.php b/lang/vendor/filament/ckb/components/button.php new file mode 100644 index 0000000..9283409 --- /dev/null +++ b/lang/vendor/filament/ckb/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'بارکردنی فایل...', + ], + +]; diff --git a/lang/vendor/filament/ckb/components/copyable.php b/lang/vendor/filament/ckb/components/copyable.php new file mode 100644 index 0000000..3dad527 --- /dev/null +++ b/lang/vendor/filament/ckb/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'لەبەرگیرا', + ], + +]; diff --git a/lang/vendor/filament/ckb/components/modal.php b/lang/vendor/filament/ckb/components/modal.php new file mode 100644 index 0000000..e731d06 --- /dev/null +++ b/lang/vendor/filament/ckb/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'داخستن', + ], + + ], + +]; diff --git a/lang/vendor/filament/ckb/components/pagination.php b/lang/vendor/filament/ckb/components/pagination.php new file mode 100644 index 0000000..29a3bd6 --- /dev/null +++ b/lang/vendor/filament/ckb/components/pagination.php @@ -0,0 +1,39 @@ + 'ڕێنوێیی پەڕەکردن', + + 'overview' => '{1} پشاندانی ئەنجامێک|[2,*] پیشاندانی :first بۆ :last لە :total ئەنجام', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'بۆ هەر پەڕەیەک', + + 'options' => [ + 'all' => 'هەموو', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'بڕۆ بۆ پەڕەی :page', + ], + + 'next' => [ + 'label' => 'دواتر', + ], + + 'previous' => [ + 'label' => 'پێشوو', + ], + + ], + +]; diff --git a/lang/vendor/filament/cs/components/button.php b/lang/vendor/filament/cs/components/button.php new file mode 100644 index 0000000..b6f054b --- /dev/null +++ b/lang/vendor/filament/cs/components/button.php @@ -0,0 +1,11 @@ + [ + + 'uploading_file' => 'Nahrávání souboru...', + + ], + +]; diff --git a/lang/vendor/filament/cs/components/copyable.php b/lang/vendor/filament/cs/components/copyable.php new file mode 100644 index 0000000..c6b1042 --- /dev/null +++ b/lang/vendor/filament/cs/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Zkopírováno', + ], + +]; diff --git a/lang/vendor/filament/cs/components/modal.php b/lang/vendor/filament/cs/components/modal.php new file mode 100644 index 0000000..47a8e24 --- /dev/null +++ b/lang/vendor/filament/cs/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Zavřít', + ], + + ], + +]; diff --git a/lang/vendor/filament/cs/components/pagination.php b/lang/vendor/filament/cs/components/pagination.php new file mode 100644 index 0000000..7c7d331 --- /dev/null +++ b/lang/vendor/filament/cs/components/pagination.php @@ -0,0 +1,45 @@ + 'Stránkování', + + 'overview' => '{1} Zobrazuji 1 výsledek|[2,*] Zobrazuji :first až :last z :total výsledků', + + 'fields' => [ + + 'records_per_page' => [ + 'label' => 'na stránku', + + 'options' => [ + 'all' => 'Vše', + ], + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'První', + ], + + 'go_to_page' => [ + 'label' => 'Jít na stránku :page', + ], + + 'last' => [ + 'label' => 'Poslední', + ], + + 'next' => [ + 'label' => 'Další', + ], + + 'previous' => [ + 'label' => 'Předchozí', + ], + + ], + +]; diff --git a/lang/vendor/filament/cy/components/copyable.php b/lang/vendor/filament/cy/components/copyable.php new file mode 100644 index 0000000..282c992 --- /dev/null +++ b/lang/vendor/filament/cy/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Wedi Copïo', + ], + +]; diff --git a/lang/vendor/filament/cy/components/pagination.php b/lang/vendor/filament/cy/components/pagination.php new file mode 100644 index 0000000..33b44aa --- /dev/null +++ b/lang/vendor/filament/cy/components/pagination.php @@ -0,0 +1,39 @@ + 'Gwe-lywio tudalennau', + + 'overview' => '{1} Dangos 1 canlyniad|[2,*] Yn dangos :first i :last o :total canlyniadau', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'fesul tudalen', + + 'options' => [ + 'all' => 'Pawb', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Ewch i dudalen :page', + ], + + 'next' => [ + 'label' => 'Nesaf', + ], + + 'previous' => [ + 'label' => 'Blaenorol', + ], + + ], + +]; diff --git a/lang/vendor/filament/da/components/button.php b/lang/vendor/filament/da/components/button.php new file mode 100644 index 0000000..ed9ffe6 --- /dev/null +++ b/lang/vendor/filament/da/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Uploader fil...', + ], + +]; diff --git a/lang/vendor/filament/da/components/copyable.php b/lang/vendor/filament/da/components/copyable.php new file mode 100644 index 0000000..47492bd --- /dev/null +++ b/lang/vendor/filament/da/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopieret', + ], + +]; diff --git a/lang/vendor/filament/da/components/modal.php b/lang/vendor/filament/da/components/modal.php new file mode 100644 index 0000000..fece422 --- /dev/null +++ b/lang/vendor/filament/da/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Luk', + ], + + ], + +]; diff --git a/lang/vendor/filament/da/components/pagination.php b/lang/vendor/filament/da/components/pagination.php new file mode 100644 index 0000000..fee1068 --- /dev/null +++ b/lang/vendor/filament/da/components/pagination.php @@ -0,0 +1,39 @@ + 'Paginering Navigation', + + 'overview' => 'Viser :first til :last af :total resultater', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'per side', + + 'options' => [ + 'all' => 'Alle', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Gå til side :page', + ], + + 'next' => [ + 'label' => 'Næste', + ], + + 'previous' => [ + 'label' => 'Forrige', + ], + + ], + +]; diff --git a/lang/vendor/filament/de/components/button.php b/lang/vendor/filament/de/components/button.php new file mode 100644 index 0000000..3586998 --- /dev/null +++ b/lang/vendor/filament/de/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Datei wird hochgeladen...', + ], + +]; diff --git a/lang/vendor/filament/de/components/copyable.php b/lang/vendor/filament/de/components/copyable.php new file mode 100644 index 0000000..0d89569 --- /dev/null +++ b/lang/vendor/filament/de/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopiert', + ], + +]; diff --git a/lang/vendor/filament/de/components/modal.php b/lang/vendor/filament/de/components/modal.php new file mode 100644 index 0000000..dfaa393 --- /dev/null +++ b/lang/vendor/filament/de/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Schließen', + ], + + ], + +]; diff --git a/lang/vendor/filament/de/components/pagination.php b/lang/vendor/filament/de/components/pagination.php new file mode 100644 index 0000000..64301da --- /dev/null +++ b/lang/vendor/filament/de/components/pagination.php @@ -0,0 +1,47 @@ + 'Seitennavigation', + + 'overview' => '{1} Zeige 1 Ergebnis|[2,*] Zeige :first bis :last von :total Ergebnissen', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'pro Seite', + + 'options' => [ + 'all' => 'Alle', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Erste', + ], + + 'go_to_page' => [ + 'label' => 'Weiter zur Seite :page', + ], + + 'last' => [ + 'label' => 'Letzte', + ], + + 'next' => [ + 'label' => 'Nächste', + ], + + 'previous' => [ + 'label' => 'Vorherige', + ], + + ], + +]; diff --git a/lang/vendor/filament/el/components/button.php b/lang/vendor/filament/el/components/button.php new file mode 100644 index 0000000..6329cc1 --- /dev/null +++ b/lang/vendor/filament/el/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Uploading file...', + ], + +]; diff --git a/lang/vendor/filament/el/components/copyable.php b/lang/vendor/filament/el/components/copyable.php new file mode 100644 index 0000000..683a0c7 --- /dev/null +++ b/lang/vendor/filament/el/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Αντιγράφηκε', + ], + +]; diff --git a/lang/vendor/filament/el/components/modal.php b/lang/vendor/filament/el/components/modal.php new file mode 100644 index 0000000..d6a944f --- /dev/null +++ b/lang/vendor/filament/el/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Άκυρο', + ], + + ], + +]; diff --git a/lang/vendor/filament/el/components/pagination.php b/lang/vendor/filament/el/components/pagination.php new file mode 100644 index 0000000..e6b488f --- /dev/null +++ b/lang/vendor/filament/el/components/pagination.php @@ -0,0 +1,47 @@ + 'Pagination navigation', + + 'overview' => '{1} Προβολή 1 αποτελέσματος|[2,*] Προβολή :first έως :last (από :total αποτελέσματα)', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Ανά σελίδα', + + 'options' => [ + 'all' => 'Όλα', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Πρώτη σελίδα', + ], + + 'go_to_page' => [ + 'label' => 'Πήγαινε στη σελίδα :page', + ], + + 'last' => [ + 'label' => 'Τελευταία σελίδα', + ], + + 'next' => [ + 'label' => 'Επόμενη', + ], + + 'previous' => [ + 'label' => 'Προηγούμενη', + ], + + ], + +]; diff --git a/lang/vendor/filament/en/components/button.php b/lang/vendor/filament/en/components/button.php new file mode 100644 index 0000000..6329cc1 --- /dev/null +++ b/lang/vendor/filament/en/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Uploading file...', + ], + +]; diff --git a/lang/vendor/filament/en/components/copyable.php b/lang/vendor/filament/en/components/copyable.php new file mode 100644 index 0000000..8c73673 --- /dev/null +++ b/lang/vendor/filament/en/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copied', + ], + +]; diff --git a/lang/vendor/filament/en/components/modal.php b/lang/vendor/filament/en/components/modal.php new file mode 100644 index 0000000..5321407 --- /dev/null +++ b/lang/vendor/filament/en/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Close', + ], + + ], + +]; diff --git a/lang/vendor/filament/en/components/pagination.php b/lang/vendor/filament/en/components/pagination.php new file mode 100644 index 0000000..6c51acd --- /dev/null +++ b/lang/vendor/filament/en/components/pagination.php @@ -0,0 +1,47 @@ + 'Pagination navigation', + + 'overview' => '{1} Showing 1 result|[2,*] Showing :first to :last of :total results', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Per page', + + 'options' => [ + 'all' => 'All', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'First', + ], + + 'go_to_page' => [ + 'label' => 'Go to page :page', + ], + + 'last' => [ + 'label' => 'Last', + ], + + 'next' => [ + 'label' => 'Next', + ], + + 'previous' => [ + 'label' => 'Previous', + ], + + ], + +]; diff --git a/lang/vendor/filament/es/components/button.php b/lang/vendor/filament/es/components/button.php new file mode 100644 index 0000000..1411349 --- /dev/null +++ b/lang/vendor/filament/es/components/button.php @@ -0,0 +1,11 @@ + [ + + 'uploading_file' => 'Subiendo archivo...', + + ], + +]; diff --git a/lang/vendor/filament/es/components/copyable.php b/lang/vendor/filament/es/components/copyable.php new file mode 100644 index 0000000..2aadb0b --- /dev/null +++ b/lang/vendor/filament/es/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copiado', + ], + +]; diff --git a/lang/vendor/filament/es/components/modal.php b/lang/vendor/filament/es/components/modal.php new file mode 100644 index 0000000..b679fc7 --- /dev/null +++ b/lang/vendor/filament/es/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Cerrar', + ], + + ], + +]; diff --git a/lang/vendor/filament/es/components/pagination.php b/lang/vendor/filament/es/components/pagination.php new file mode 100644 index 0000000..b8e9377 --- /dev/null +++ b/lang/vendor/filament/es/components/pagination.php @@ -0,0 +1,47 @@ + 'Navegación de paginación', + + 'overview' => '{1} Se muestra un resultado|[2,*] Se muestran de :first a :last de :total resultados', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'por página', + + 'options' => [ + 'all' => 'Todos', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Primera', + ], + + 'go_to_page' => [ + 'label' => 'Ir a la página :page', + ], + + 'last' => [ + 'label' => 'Última', + ], + + 'next' => [ + 'label' => 'Siguiente', + ], + + 'previous' => [ + 'label' => 'Anterior', + ], + + ], + +]; diff --git a/lang/vendor/filament/eu/components/button.php b/lang/vendor/filament/eu/components/button.php new file mode 100644 index 0000000..8af7f16 --- /dev/null +++ b/lang/vendor/filament/eu/components/button.php @@ -0,0 +1,11 @@ + [ + + 'uploading_file' => 'Artxiboa igotzen...', + + ], + +]; diff --git a/lang/vendor/filament/eu/components/copyable.php b/lang/vendor/filament/eu/components/copyable.php new file mode 100644 index 0000000..3e35961 --- /dev/null +++ b/lang/vendor/filament/eu/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopiatuta', + ], + +]; diff --git a/lang/vendor/filament/eu/components/modal.php b/lang/vendor/filament/eu/components/modal.php new file mode 100644 index 0000000..ce784f0 --- /dev/null +++ b/lang/vendor/filament/eu/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Itxi', + ], + + ], + +]; diff --git a/lang/vendor/filament/eu/components/pagination.php b/lang/vendor/filament/eu/components/pagination.php new file mode 100644 index 0000000..8b35202 --- /dev/null +++ b/lang/vendor/filament/eu/components/pagination.php @@ -0,0 +1,39 @@ + 'Paginazioaren nabigazioa', + + 'overview' => '{1} Emaitza bat erakusten da|[2,*] :total emaitzatik :firstetik :lastera erakusten dira', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'orriko', + + 'options' => [ + 'all' => 'Denak', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Joan :page orrira', + ], + + 'next' => [ + 'label' => 'Hurrengoa', + ], + + 'previous' => [ + 'label' => 'Aurrekoa', + ], + + ], + +]; diff --git a/lang/vendor/filament/fa/components/button.php b/lang/vendor/filament/fa/components/button.php new file mode 100644 index 0000000..289a81d --- /dev/null +++ b/lang/vendor/filament/fa/components/button.php @@ -0,0 +1,11 @@ + [ + + 'uploading_file' => 'درحال آپلود فایل...', + + ], + +]; diff --git a/lang/vendor/filament/fa/components/copyable.php b/lang/vendor/filament/fa/components/copyable.php new file mode 100644 index 0000000..c5a2eb5 --- /dev/null +++ b/lang/vendor/filament/fa/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'کپی شد', + ], + +]; diff --git a/lang/vendor/filament/fa/components/modal.php b/lang/vendor/filament/fa/components/modal.php new file mode 100644 index 0000000..cc0779a --- /dev/null +++ b/lang/vendor/filament/fa/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'بستن', + ], + + ], + +]; diff --git a/lang/vendor/filament/fa/components/pagination.php b/lang/vendor/filament/fa/components/pagination.php new file mode 100644 index 0000000..92c870b --- /dev/null +++ b/lang/vendor/filament/fa/components/pagination.php @@ -0,0 +1,39 @@ + 'صفحه بندی', + + 'overview' => 'در حال نمایش :first به :last از :total نتیجه', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'در هر صفحه', + + 'options' => [ + 'all' => 'همه', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'برو به صفحه :page', + ], + + 'next' => [ + 'label' => 'بعدی', + ], + + 'previous' => [ + 'label' => 'قبلی', + ], + + ], + +]; diff --git a/lang/vendor/filament/fi/components/button.php b/lang/vendor/filament/fi/components/button.php new file mode 100644 index 0000000..08ab89b --- /dev/null +++ b/lang/vendor/filament/fi/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Siirretään tiedostoa...', + ], + +]; diff --git a/lang/vendor/filament/fi/components/copyable.php b/lang/vendor/filament/fi/components/copyable.php new file mode 100644 index 0000000..9b21276 --- /dev/null +++ b/lang/vendor/filament/fi/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopioitu', + ], + +]; diff --git a/lang/vendor/filament/fi/components/modal.php b/lang/vendor/filament/fi/components/modal.php new file mode 100644 index 0000000..999d1cb --- /dev/null +++ b/lang/vendor/filament/fi/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Sulje', + ], + + ], + +]; diff --git a/lang/vendor/filament/fi/components/pagination.php b/lang/vendor/filament/fi/components/pagination.php new file mode 100644 index 0000000..859ba14 --- /dev/null +++ b/lang/vendor/filament/fi/components/pagination.php @@ -0,0 +1,47 @@ + 'Sivujen navigointi', + + 'overview' => '{1} Näytetään 1 tulos|[2,*] Näytetään :first - :last / :total tulosta', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'per sivu', + + 'options' => [ + 'all' => 'Kaikki', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Ensimmäinen', + ], + + 'go_to_page' => [ + 'label' => 'Mene sivulle :page', + ], + + 'last' => [ + 'label' => 'Viimeinen', + ], + + 'next' => [ + 'label' => 'Seuraava', + ], + + 'previous' => [ + 'label' => 'Edellinen', + ], + + ], + +]; diff --git a/lang/vendor/filament/fr/components/button.php b/lang/vendor/filament/fr/components/button.php new file mode 100644 index 0000000..68afd72 --- /dev/null +++ b/lang/vendor/filament/fr/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Chargement du fichier...', + ], + +]; diff --git a/lang/vendor/filament/fr/components/copyable.php b/lang/vendor/filament/fr/components/copyable.php new file mode 100644 index 0000000..e4c1897 --- /dev/null +++ b/lang/vendor/filament/fr/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copié', + ], + +]; diff --git a/lang/vendor/filament/fr/components/modal.php b/lang/vendor/filament/fr/components/modal.php new file mode 100644 index 0000000..22ddd7f --- /dev/null +++ b/lang/vendor/filament/fr/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Fermer', + ], + + ], + +]; diff --git a/lang/vendor/filament/fr/components/pagination.php b/lang/vendor/filament/fr/components/pagination.php new file mode 100644 index 0000000..e6ddbf6 --- /dev/null +++ b/lang/vendor/filament/fr/components/pagination.php @@ -0,0 +1,47 @@ + 'Navigation par pagination', + + 'overview' => '{1} Affichage de 1 résultat|[2,*] Affichage de :first à :last sur :total résultats', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'par page', + + 'options' => [ + 'all' => 'Tous', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Aller à la page :page', + ], + + 'next' => [ + 'label' => 'Suivant', + ], + + 'previous' => [ + 'label' => 'Précédent', + ], + + 'first' => [ + 'label' => 'Première', + ], + + 'last' => [ + 'label' => 'Dernière', + ], + + ], + +]; diff --git a/lang/vendor/filament/he/components/button.php b/lang/vendor/filament/he/components/button.php new file mode 100644 index 0000000..5919b5d --- /dev/null +++ b/lang/vendor/filament/he/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'מעלה קבצים...', + ], + +]; diff --git a/lang/vendor/filament/he/components/copyable.php b/lang/vendor/filament/he/components/copyable.php new file mode 100644 index 0000000..a36d5b9 --- /dev/null +++ b/lang/vendor/filament/he/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'הועתק', + ], + +]; diff --git a/lang/vendor/filament/he/components/modal.php b/lang/vendor/filament/he/components/modal.php new file mode 100644 index 0000000..517d823 --- /dev/null +++ b/lang/vendor/filament/he/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'סגור', + ], + + ], + +]; diff --git a/lang/vendor/filament/he/components/pagination.php b/lang/vendor/filament/he/components/pagination.php new file mode 100644 index 0000000..404004f --- /dev/null +++ b/lang/vendor/filament/he/components/pagination.php @@ -0,0 +1,39 @@ + 'הצגת רשומות', + + 'overview' => 'מציג :first - :last מתוך :total תוצאות', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'בעמוד', + + 'options' => [ + 'all' => 'הכל', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'נווט לעמוד :page', + ], + + 'next' => [ + 'label' => 'הבא', + ], + + 'previous' => [ + 'label' => 'הקודם', + ], + + ], + +]; diff --git a/lang/vendor/filament/hi/components/pagination.php b/lang/vendor/filament/hi/components/pagination.php new file mode 100644 index 0000000..4ee8822 --- /dev/null +++ b/lang/vendor/filament/hi/components/pagination.php @@ -0,0 +1,33 @@ + 'पृष्ठ मार्गदर्शन', + + 'overview' => ':first से :last प्रविष्टियां :total में से', + + 'fields' => [ + + 'records_per_page' => [ + 'label' => 'प्रति पृष्ठ', + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'पृष्ठ :page पर जाएं', + ], + + 'next' => [ + 'label' => 'अगला', + ], + + 'previous' => [ + 'label' => 'पिछला', + ], + + ], + +]; diff --git a/lang/vendor/filament/hr/components/button.php b/lang/vendor/filament/hr/components/button.php new file mode 100644 index 0000000..8f22854 --- /dev/null +++ b/lang/vendor/filament/hr/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Prenosim datoteku...', + ], + +]; diff --git a/lang/vendor/filament/hr/components/copyable.php b/lang/vendor/filament/hr/components/copyable.php new file mode 100644 index 0000000..0741c30 --- /dev/null +++ b/lang/vendor/filament/hr/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopirano', + ], + +]; diff --git a/lang/vendor/filament/hr/components/modal.php b/lang/vendor/filament/hr/components/modal.php new file mode 100644 index 0000000..3f49931 --- /dev/null +++ b/lang/vendor/filament/hr/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Zatvori', + ], + + ], + +]; diff --git a/lang/vendor/filament/hr/components/pagination.php b/lang/vendor/filament/hr/components/pagination.php new file mode 100644 index 0000000..6744807 --- /dev/null +++ b/lang/vendor/filament/hr/components/pagination.php @@ -0,0 +1,47 @@ + 'Navigacija stranicama', + + 'overview' => '{1} Prikazuje se 1 rezultat|[2,*] Prikazuje se :first do :last od ukupno :total rezultata', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Po stranici', + + 'options' => [ + 'all' => 'Sve', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Prva', + ], + + 'go_to_page' => [ + 'label' => 'Idi na stranicu :page', + ], + + 'last' => [ + 'label' => 'Zadnja', + ], + + 'next' => [ + 'label' => 'Naprijed', + ], + + 'previous' => [ + 'label' => 'Natrag', + ], + + ], + +]; diff --git a/lang/vendor/filament/hu/components/button.php b/lang/vendor/filament/hu/components/button.php new file mode 100644 index 0000000..840c392 --- /dev/null +++ b/lang/vendor/filament/hu/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Fájl feltöltése...', + ], + +]; diff --git a/lang/vendor/filament/hu/components/copyable.php b/lang/vendor/filament/hu/components/copyable.php new file mode 100644 index 0000000..680fa07 --- /dev/null +++ b/lang/vendor/filament/hu/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kimásolva', + ], + +]; diff --git a/lang/vendor/filament/hu/components/modal.php b/lang/vendor/filament/hu/components/modal.php new file mode 100644 index 0000000..64eb231 --- /dev/null +++ b/lang/vendor/filament/hu/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Bezárás', + ], + + ], + +]; diff --git a/lang/vendor/filament/hu/components/pagination.php b/lang/vendor/filament/hu/components/pagination.php new file mode 100644 index 0000000..be6a258 --- /dev/null +++ b/lang/vendor/filament/hu/components/pagination.php @@ -0,0 +1,47 @@ + 'Lapozás', + + 'overview' => '{1} 1 találat|[2,*] :first - :last megjelenítve a(z) :total találatból', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Sorok száma:', + + 'options' => [ + 'all' => 'Összes', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Első', + ], + + 'go_to_page' => [ + 'label' => 'Ugrás az oldalra: :page', + ], + + 'last' => [ + 'label' => 'Utolsó', + ], + + 'next' => [ + 'label' => 'Következő', + ], + + 'previous' => [ + 'label' => 'Előző', + ], + + ], + +]; diff --git a/lang/vendor/filament/hy/components/button.php b/lang/vendor/filament/hy/components/button.php new file mode 100644 index 0000000..c470508 --- /dev/null +++ b/lang/vendor/filament/hy/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Ֆայլի վերբեռնում...', + ], + +]; diff --git a/lang/vendor/filament/hy/components/copyable.php b/lang/vendor/filament/hy/components/copyable.php new file mode 100644 index 0000000..1d22117 --- /dev/null +++ b/lang/vendor/filament/hy/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Պատճենված է', + ], + +]; diff --git a/lang/vendor/filament/hy/components/modal.php b/lang/vendor/filament/hy/components/modal.php new file mode 100644 index 0000000..f275697 --- /dev/null +++ b/lang/vendor/filament/hy/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Փակել', + ], + + ], + +]; diff --git a/lang/vendor/filament/hy/components/pagination.php b/lang/vendor/filament/hy/components/pagination.php new file mode 100644 index 0000000..e6cfad6 --- /dev/null +++ b/lang/vendor/filament/hy/components/pagination.php @@ -0,0 +1,47 @@ + 'Էջավորման նավիգացիա', + + 'overview' => 'Ցուցադրվում են :total արդյունքներից :first-ից :last-ը', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Մեկ էջում', + + 'options' => [ + 'all' => 'Բոլորը', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Առաջինը', + ], + + 'go_to_page' => [ + 'label' => 'Գնալ էջ :page', + ], + + 'last' => [ + 'label' => 'Վերջինը', + ], + + 'next' => [ + 'label' => 'Հաջորդը', + ], + + 'previous' => [ + 'label' => 'Նախորդը', + ], + + ], + +]; diff --git a/lang/vendor/filament/id/components/button.php b/lang/vendor/filament/id/components/button.php new file mode 100644 index 0000000..8d03da9 --- /dev/null +++ b/lang/vendor/filament/id/components/button.php @@ -0,0 +1,11 @@ + [ + + 'uploading_file' => 'Mengunggah berkas...', + + ], + +]; diff --git a/lang/vendor/filament/id/components/copyable.php b/lang/vendor/filament/id/components/copyable.php new file mode 100644 index 0000000..4530fd5 --- /dev/null +++ b/lang/vendor/filament/id/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Disalin', + ], + +]; diff --git a/lang/vendor/filament/id/components/modal.php b/lang/vendor/filament/id/components/modal.php new file mode 100644 index 0000000..736df38 --- /dev/null +++ b/lang/vendor/filament/id/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Tutup', + ], + + ], + +]; diff --git a/lang/vendor/filament/id/components/pagination.php b/lang/vendor/filament/id/components/pagination.php new file mode 100644 index 0000000..7d78319 --- /dev/null +++ b/lang/vendor/filament/id/components/pagination.php @@ -0,0 +1,47 @@ + 'Navigasi halaman', + + 'overview' => 'Menampilkan :first sampai :last dari :total hasil', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'per halaman', + + 'options' => [ + 'all' => 'Semua', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Pertama', + ], + + 'go_to_page' => [ + 'label' => 'Ke halaman :page', + ], + + 'last' => [ + 'label' => 'Terakhir', + ], + + 'next' => [ + 'label' => 'Selanjutnya', + ], + + 'previous' => [ + 'label' => 'Sebelumnya', + ], + + ], + +]; diff --git a/lang/vendor/filament/it/components/button.php b/lang/vendor/filament/it/components/button.php new file mode 100644 index 0000000..0e0fe5a --- /dev/null +++ b/lang/vendor/filament/it/components/button.php @@ -0,0 +1,11 @@ + [ + + 'uploading_file' => 'Caricamento file...', + + ], + +]; diff --git a/lang/vendor/filament/it/components/copyable.php b/lang/vendor/filament/it/components/copyable.php new file mode 100644 index 0000000..8ac0842 --- /dev/null +++ b/lang/vendor/filament/it/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copiato', + ], + +]; diff --git a/lang/vendor/filament/it/components/modal.php b/lang/vendor/filament/it/components/modal.php new file mode 100644 index 0000000..cff4e7e --- /dev/null +++ b/lang/vendor/filament/it/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Chiudi', + ], + + ], + +]; diff --git a/lang/vendor/filament/it/components/pagination.php b/lang/vendor/filament/it/components/pagination.php new file mode 100644 index 0000000..88ee75b --- /dev/null +++ b/lang/vendor/filament/it/components/pagination.php @@ -0,0 +1,39 @@ + 'Navigazione paginazione', + + 'overview' => 'Mostrati da :first a :last di :total risultati', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'per pagina', + + 'options' => [ + 'all' => 'Tutti', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Vai a pagina :page', + ], + + 'next' => [ + 'label' => 'Successivo', + ], + + 'previous' => [ + 'label' => 'Precedente', + ], + + ], + +]; diff --git a/lang/vendor/filament/ja/components/button.php b/lang/vendor/filament/ja/components/button.php new file mode 100644 index 0000000..7a0d282 --- /dev/null +++ b/lang/vendor/filament/ja/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'ファイルをアップロード中...', + ], + +]; diff --git a/lang/vendor/filament/ja/components/copyable.php b/lang/vendor/filament/ja/components/copyable.php new file mode 100644 index 0000000..653cc85 --- /dev/null +++ b/lang/vendor/filament/ja/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'コピーしました', + ], + +]; diff --git a/lang/vendor/filament/ja/components/modal.php b/lang/vendor/filament/ja/components/modal.php new file mode 100644 index 0000000..beb37a5 --- /dev/null +++ b/lang/vendor/filament/ja/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => '閉じる', + ], + + ], + +]; diff --git a/lang/vendor/filament/ja/components/pagination.php b/lang/vendor/filament/ja/components/pagination.php new file mode 100644 index 0000000..8c7f9b3 --- /dev/null +++ b/lang/vendor/filament/ja/components/pagination.php @@ -0,0 +1,47 @@ + 'ページネーション', + + 'overview' => ':total件中:first件目から:last件目を表示', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => '件を表示', + + 'options' => [ + 'all' => 'すべて', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => '最初', + ], + + 'go_to_page' => [ + 'label' => ':pageページへ移動', + ], + + 'last' => [ + 'label' => '最後', + ], + + 'next' => [ + 'label' => '次', + ], + + 'previous' => [ + 'label' => '前', + ], + + ], + +]; diff --git a/lang/vendor/filament/ka/components/button.php b/lang/vendor/filament/ka/components/button.php new file mode 100644 index 0000000..bf87b0a --- /dev/null +++ b/lang/vendor/filament/ka/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'ფაილის ატვირთვა...', + ], + +]; diff --git a/lang/vendor/filament/ka/components/copyable.php b/lang/vendor/filament/ka/components/copyable.php new file mode 100644 index 0000000..69e5ec8 --- /dev/null +++ b/lang/vendor/filament/ka/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'დაკოპირდა', + ], + +]; diff --git a/lang/vendor/filament/ka/components/modal.php b/lang/vendor/filament/ka/components/modal.php new file mode 100644 index 0000000..23f2ccf --- /dev/null +++ b/lang/vendor/filament/ka/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'დახურვა', + ], + + ], + +]; diff --git a/lang/vendor/filament/ka/components/pagination.php b/lang/vendor/filament/ka/components/pagination.php new file mode 100644 index 0000000..dceb805 --- /dev/null +++ b/lang/vendor/filament/ka/components/pagination.php @@ -0,0 +1,47 @@ + 'გვერდების ნავიგაცია', + + 'overview' => '{1} ნაჩვენებია 1 შედეგი|[2,*] ნაჩვენებია :first-დან :last-მდე :total შედეგიდან', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'გვერდზე', + + 'options' => [ + 'all' => 'ყველა', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'პირველი', + ], + + 'go_to_page' => [ + 'label' => 'გადადით გვერდზე :page', + ], + + 'last' => [ + 'label' => 'ბოლო', + ], + + 'next' => [ + 'label' => 'შემდეგი', + ], + + 'previous' => [ + 'label' => 'წინა', + ], + + ], + +]; diff --git a/lang/vendor/filament/km/components/button.php b/lang/vendor/filament/km/components/button.php new file mode 100644 index 0000000..ace6b69 --- /dev/null +++ b/lang/vendor/filament/km/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'កំពុងបង្ហោះឯកសារ...', + ], + +]; diff --git a/lang/vendor/filament/km/components/copyable.php b/lang/vendor/filament/km/components/copyable.php new file mode 100644 index 0000000..d0ef0c5 --- /dev/null +++ b/lang/vendor/filament/km/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'ចម្លង', + ], + +]; diff --git a/lang/vendor/filament/km/components/modal.php b/lang/vendor/filament/km/components/modal.php new file mode 100644 index 0000000..3403477 --- /dev/null +++ b/lang/vendor/filament/km/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'បិទ', + ], + + ], + +]; diff --git a/lang/vendor/filament/km/components/pagination.php b/lang/vendor/filament/km/components/pagination.php new file mode 100644 index 0000000..c6efdf2 --- /dev/null +++ b/lang/vendor/filament/km/components/pagination.php @@ -0,0 +1,47 @@ + 'ការរុករក Pagination', + + 'overview' => '{1} ការបង្កាញលទ្ធផល ១ |[2,*] ការបង្ហាញ :first ដល់ :last នៃ :total លទ្ធផល', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'ក្នុងមួយទំព័រ', + + 'options' => [ + 'all' => 'ទាំងអស់។', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'ទីមួយ', + ], + + 'go_to_page' => [ + 'label' => 'ទៅកាន់ទំព័រ :page', + ], + + 'last' => [ + 'label' => 'ចុងក្រោយ', + ], + + 'next' => [ + 'label' => 'បន្ទាប់', + ], + + 'previous' => [ + 'label' => 'មុន', + ], + + ], + +]; diff --git a/lang/vendor/filament/ko/components/button.php b/lang/vendor/filament/ko/components/button.php new file mode 100644 index 0000000..33c38b9 --- /dev/null +++ b/lang/vendor/filament/ko/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => '파일 업로드 ...', + ], + +]; diff --git a/lang/vendor/filament/ko/components/copyable.php b/lang/vendor/filament/ko/components/copyable.php new file mode 100644 index 0000000..e5715bc --- /dev/null +++ b/lang/vendor/filament/ko/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => '복사 완료', + ], + +]; diff --git a/lang/vendor/filament/ko/components/modal.php b/lang/vendor/filament/ko/components/modal.php new file mode 100644 index 0000000..1c7314f --- /dev/null +++ b/lang/vendor/filament/ko/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => '닫기', + ], + + ], + +]; diff --git a/lang/vendor/filament/ko/components/pagination.php b/lang/vendor/filament/ko/components/pagination.php new file mode 100644 index 0000000..466bd68 --- /dev/null +++ b/lang/vendor/filament/ko/components/pagination.php @@ -0,0 +1,47 @@ + '페이지 탐색', + + 'overview' => ':total 건 중 :first 건부터 :last 건까지 보기', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => '페이지 당', + + 'options' => [ + 'all' => '전체', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => '첫 페이지', + ], + + 'go_to_page' => [ + 'label' => ':page 페이지로 이동', + ], + + 'last' => [ + 'label' => '마지막 페이지', + ], + + 'next' => [ + 'label' => '다음', + ], + + 'previous' => [ + 'label' => '이전', + ], + + ], + +]; diff --git a/lang/vendor/filament/ku/components/button.php b/lang/vendor/filament/ku/components/button.php new file mode 100644 index 0000000..9283409 --- /dev/null +++ b/lang/vendor/filament/ku/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'بارکردنی فایل...', + ], + +]; diff --git a/lang/vendor/filament/ku/components/copyable.php b/lang/vendor/filament/ku/components/copyable.php new file mode 100644 index 0000000..3dad527 --- /dev/null +++ b/lang/vendor/filament/ku/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'لەبەرگیرا', + ], + +]; diff --git a/lang/vendor/filament/ku/components/modal.php b/lang/vendor/filament/ku/components/modal.php new file mode 100644 index 0000000..e731d06 --- /dev/null +++ b/lang/vendor/filament/ku/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'داخستن', + ], + + ], + +]; diff --git a/lang/vendor/filament/ku/components/pagination.php b/lang/vendor/filament/ku/components/pagination.php new file mode 100644 index 0000000..29a3bd6 --- /dev/null +++ b/lang/vendor/filament/ku/components/pagination.php @@ -0,0 +1,39 @@ + 'ڕێنوێیی پەڕەکردن', + + 'overview' => '{1} پشاندانی ئەنجامێک|[2,*] پیشاندانی :first بۆ :last لە :total ئەنجام', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'بۆ هەر پەڕەیەک', + + 'options' => [ + 'all' => 'هەموو', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'بڕۆ بۆ پەڕەی :page', + ], + + 'next' => [ + 'label' => 'دواتر', + ], + + 'previous' => [ + 'label' => 'پێشوو', + ], + + ], + +]; diff --git a/lang/vendor/filament/lt/components/button.php b/lang/vendor/filament/lt/components/button.php new file mode 100644 index 0000000..013b0f9 --- /dev/null +++ b/lang/vendor/filament/lt/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Įkeliamas failas...', + ], + +]; diff --git a/lang/vendor/filament/lt/components/copyable.php b/lang/vendor/filament/lt/components/copyable.php new file mode 100644 index 0000000..4aab22f --- /dev/null +++ b/lang/vendor/filament/lt/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Nukopijuota', + ], + +]; diff --git a/lang/vendor/filament/lt/components/modal.php b/lang/vendor/filament/lt/components/modal.php new file mode 100644 index 0000000..1c2ea3d --- /dev/null +++ b/lang/vendor/filament/lt/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Uždaryti', + ], + + ], + +]; diff --git a/lang/vendor/filament/lt/components/pagination.php b/lang/vendor/filament/lt/components/pagination.php new file mode 100644 index 0000000..4a243cd --- /dev/null +++ b/lang/vendor/filament/lt/components/pagination.php @@ -0,0 +1,47 @@ + 'Puslapiavimo navigacija', + + 'overview' => 'Rodomi nuo :first iki :last rezultatai iš :total', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'puslapyje', + + 'options' => [ + 'all' => 'Viską', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Pirmas', + ], + + 'go_to_page' => [ + 'label' => 'Eiti į puslapį :page', + ], + + 'last' => [ + 'label' => 'Paskutinis', + ], + + 'next' => [ + 'label' => 'Kitas', + ], + + 'previous' => [ + 'label' => 'Buvęs', + ], + + ], + +]; diff --git a/lang/vendor/filament/lv/components/button.php b/lang/vendor/filament/lv/components/button.php new file mode 100644 index 0000000..d61aad9 --- /dev/null +++ b/lang/vendor/filament/lv/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Notiek faila augšupielāde...', + ], + +]; diff --git a/lang/vendor/filament/lv/components/copyable.php b/lang/vendor/filament/lv/components/copyable.php new file mode 100644 index 0000000..9cf15fc --- /dev/null +++ b/lang/vendor/filament/lv/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopēts', + ], + +]; diff --git a/lang/vendor/filament/lv/components/modal.php b/lang/vendor/filament/lv/components/modal.php new file mode 100644 index 0000000..54b6fc2 --- /dev/null +++ b/lang/vendor/filament/lv/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Aizvērt', + ], + + ], + +]; diff --git a/lang/vendor/filament/lv/components/pagination.php b/lang/vendor/filament/lv/components/pagination.php new file mode 100644 index 0000000..398cfad --- /dev/null +++ b/lang/vendor/filament/lv/components/pagination.php @@ -0,0 +1,39 @@ + 'Lapdales navigācija', + + 'overview' => '{1} Rāda 1 rezultātu|[2,*] Rāda :first līdz :last no :total rezultātiem', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'vienā lappusē', + + 'options' => [ + 'all' => 'Visi', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Doties uz lapu :page', + ], + + 'next' => [ + 'label' => 'Nākamais', + ], + + 'previous' => [ + 'label' => 'Iepriekšējais', + ], + + ], + +]; diff --git a/lang/vendor/filament/mn/components/button.php b/lang/vendor/filament/mn/components/button.php new file mode 100644 index 0000000..3c4b3ca --- /dev/null +++ b/lang/vendor/filament/mn/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Хуулж байна...', + ], + +]; diff --git a/lang/vendor/filament/mn/components/copyable.php b/lang/vendor/filament/mn/components/copyable.php new file mode 100644 index 0000000..7ae290c --- /dev/null +++ b/lang/vendor/filament/mn/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Хуулав', + ], + +]; diff --git a/lang/vendor/filament/mn/components/modal.php b/lang/vendor/filament/mn/components/modal.php new file mode 100644 index 0000000..feb94d0 --- /dev/null +++ b/lang/vendor/filament/mn/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Хаах', + ], + + ], + +]; diff --git a/lang/vendor/filament/mn/components/pagination.php b/lang/vendor/filament/mn/components/pagination.php new file mode 100644 index 0000000..c4c246b --- /dev/null +++ b/lang/vendor/filament/mn/components/pagination.php @@ -0,0 +1,47 @@ + 'Хуудас', + + 'overview' => '{1} Нийт 1 |[2,*] Нийт :total бичлэг :first - :last', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'хуудас бүр', + + 'options' => [ + 'all' => 'Бүгд', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Эхний', + ], + + 'go_to_page' => [ + 'label' => 'Хуудас руу очих :page', + ], + + 'last' => [ + 'label' => 'Сүүлийн', + ], + + 'next' => [ + 'label' => 'Дараах', + ], + + 'previous' => [ + 'label' => 'Өмнөх', + ], + + ], + +]; diff --git a/lang/vendor/filament/ms/components/button.php b/lang/vendor/filament/ms/components/button.php new file mode 100644 index 0000000..da857fb --- /dev/null +++ b/lang/vendor/filament/ms/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Memuat naik fail...', + ], + +]; diff --git a/lang/vendor/filament/ms/components/copyable.php b/lang/vendor/filament/ms/components/copyable.php new file mode 100644 index 0000000..4530fd5 --- /dev/null +++ b/lang/vendor/filament/ms/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Disalin', + ], + +]; diff --git a/lang/vendor/filament/ms/components/modal.php b/lang/vendor/filament/ms/components/modal.php new file mode 100644 index 0000000..736df38 --- /dev/null +++ b/lang/vendor/filament/ms/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Tutup', + ], + + ], + +]; diff --git a/lang/vendor/filament/ms/components/pagination.php b/lang/vendor/filament/ms/components/pagination.php new file mode 100644 index 0000000..e3ccd51 --- /dev/null +++ b/lang/vendor/filament/ms/components/pagination.php @@ -0,0 +1,47 @@ + 'Navigasi penomboran', + + 'overview' => '{1} Memaparkan 1 rekod|Memaparkan :first hingga :last daripada :total rekod', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'per halaman', + + 'options' => [ + 'all' => 'Semua', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Pertama', + ], + + 'go_to_page' => [ + 'label' => 'Pergi ke halaman :page', + ], + + 'last' => [ + 'label' => 'Akhir', + ], + + 'next' => [ + 'label' => 'Seterusnya', + ], + + 'previous' => [ + 'label' => 'Sebelumnya', + ], + + ], + +]; diff --git a/lang/vendor/filament/nl/components/button.php b/lang/vendor/filament/nl/components/button.php new file mode 100644 index 0000000..c02840c --- /dev/null +++ b/lang/vendor/filament/nl/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Bestand uploaden...', + ], + +]; diff --git a/lang/vendor/filament/nl/components/copyable.php b/lang/vendor/filament/nl/components/copyable.php new file mode 100644 index 0000000..a86f399 --- /dev/null +++ b/lang/vendor/filament/nl/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Gekopieerd', + ], + +]; diff --git a/lang/vendor/filament/nl/components/modal.php b/lang/vendor/filament/nl/components/modal.php new file mode 100644 index 0000000..b0c5728 --- /dev/null +++ b/lang/vendor/filament/nl/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Sluiten', + ], + + ], + +]; diff --git a/lang/vendor/filament/nl/components/pagination.php b/lang/vendor/filament/nl/components/pagination.php new file mode 100644 index 0000000..75215f5 --- /dev/null +++ b/lang/vendor/filament/nl/components/pagination.php @@ -0,0 +1,47 @@ + 'Paginering navigatie', + + 'overview' => '{1} Toont 1 resultaat|[2,*] Toont :first tot :last van :total resultaten', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Per pagina', + + 'options' => [ + 'all' => 'Alles', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Eerste', + ], + + 'go_to_page' => [ + 'label' => 'Ga naar pagina :page', + ], + + 'last' => [ + 'label' => 'Laatste', + ], + + 'next' => [ + 'label' => 'Volgende', + ], + + 'previous' => [ + 'label' => 'Vorige', + ], + + ], + +]; diff --git a/lang/vendor/filament/no/components/button.php b/lang/vendor/filament/no/components/button.php new file mode 100644 index 0000000..1eff00e --- /dev/null +++ b/lang/vendor/filament/no/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Laster opp fil...', + ], + +]; diff --git a/lang/vendor/filament/no/components/copyable.php b/lang/vendor/filament/no/components/copyable.php new file mode 100644 index 0000000..0d89569 --- /dev/null +++ b/lang/vendor/filament/no/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopiert', + ], + +]; diff --git a/lang/vendor/filament/no/components/modal.php b/lang/vendor/filament/no/components/modal.php new file mode 100644 index 0000000..1bc9323 --- /dev/null +++ b/lang/vendor/filament/no/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Lukk', + ], + + ], + +]; diff --git a/lang/vendor/filament/no/components/pagination.php b/lang/vendor/filament/no/components/pagination.php new file mode 100644 index 0000000..ecab6ec --- /dev/null +++ b/lang/vendor/filament/no/components/pagination.php @@ -0,0 +1,47 @@ + 'Sidenavigering', + + 'overview' => '{1} Viser 1 resultat|[2,*] Viser :first til :last av :total resultater', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Pr. side', + + 'options' => [ + 'all' => 'Alle', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Første', + ], + + 'go_to_page' => [ + 'label' => 'Gå til side :page', + ], + + 'last' => [ + 'label' => 'Siste', + ], + + 'next' => [ + 'label' => 'Neste', + ], + + 'previous' => [ + 'label' => 'Forrige', + ], + + ], + +]; diff --git a/lang/vendor/filament/np/components/button.php b/lang/vendor/filament/np/components/button.php new file mode 100644 index 0000000..ba18ccd --- /dev/null +++ b/lang/vendor/filament/np/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'फाइल अपलोड गर्दै...', + ], + +]; diff --git a/lang/vendor/filament/np/components/copyable.php b/lang/vendor/filament/np/components/copyable.php new file mode 100644 index 0000000..fab3e53 --- /dev/null +++ b/lang/vendor/filament/np/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'प्रतिलिपि गरियो', + ], + +]; diff --git a/lang/vendor/filament/np/components/modal.php b/lang/vendor/filament/np/components/modal.php new file mode 100644 index 0000000..e2cef93 --- /dev/null +++ b/lang/vendor/filament/np/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'बन्द गर्नुहोस्', + ], + + ], + +]; diff --git a/lang/vendor/filament/np/components/pagination.php b/lang/vendor/filament/np/components/pagination.php new file mode 100644 index 0000000..9ff65e7 --- /dev/null +++ b/lang/vendor/filament/np/components/pagination.php @@ -0,0 +1,39 @@ + 'पृष्ठांकन नेभिगेसन', + + 'overview' => '{1} एउटा परिणाम देखाउँदै|[2,*] :total नतिजा मध्ये :first देखि :last देखाउँदै', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'प्रति पृष्ठ', + + 'options' => [ + 'all' => 'सबै', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'पृष्ठ :page मा जानुहोस्', + ], + + 'next' => [ + 'label' => 'अर्को', + ], + + 'previous' => [ + 'label' => 'अघिल्लो', + ], + + ], + +]; diff --git a/lang/vendor/filament/pl/components/button.php b/lang/vendor/filament/pl/components/button.php new file mode 100644 index 0000000..a8ae3de --- /dev/null +++ b/lang/vendor/filament/pl/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Wysyłanie pliku...', + ], + +]; diff --git a/lang/vendor/filament/pl/components/copyable.php b/lang/vendor/filament/pl/components/copyable.php new file mode 100644 index 0000000..8e3875c --- /dev/null +++ b/lang/vendor/filament/pl/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Skopiowano', + ], + +]; diff --git a/lang/vendor/filament/pl/components/modal.php b/lang/vendor/filament/pl/components/modal.php new file mode 100644 index 0000000..008c639 --- /dev/null +++ b/lang/vendor/filament/pl/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Zamknij', + ], + + ], + +]; diff --git a/lang/vendor/filament/pl/components/pagination.php b/lang/vendor/filament/pl/components/pagination.php new file mode 100644 index 0000000..9e13f0f --- /dev/null +++ b/lang/vendor/filament/pl/components/pagination.php @@ -0,0 +1,47 @@ + 'Paginacja', + + 'overview' => 'Pozycje od :first do :last z :total łącznie', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'na stronę', + + 'options' => [ + 'all' => 'Wszystkie', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Pierwsza', + ], + + 'go_to_page' => [ + 'label' => 'Przejdź do strony :page', + ], + + 'last' => [ + 'label' => 'Osatnia', + ], + + 'next' => [ + 'label' => 'Następna', + ], + + 'previous' => [ + 'label' => 'Poprzednia', + ], + + ], + +]; diff --git a/lang/vendor/filament/pt_BR/components/button.php b/lang/vendor/filament/pt_BR/components/button.php new file mode 100644 index 0000000..bfd0a52 --- /dev/null +++ b/lang/vendor/filament/pt_BR/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Enviando arquivo...', + ], + +]; diff --git a/lang/vendor/filament/pt_BR/components/copyable.php b/lang/vendor/filament/pt_BR/components/copyable.php new file mode 100644 index 0000000..2aadb0b --- /dev/null +++ b/lang/vendor/filament/pt_BR/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copiado', + ], + +]; diff --git a/lang/vendor/filament/pt_BR/components/modal.php b/lang/vendor/filament/pt_BR/components/modal.php new file mode 100644 index 0000000..6759dad --- /dev/null +++ b/lang/vendor/filament/pt_BR/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Fechar', + ], + + ], + +]; diff --git a/lang/vendor/filament/pt_BR/components/pagination.php b/lang/vendor/filament/pt_BR/components/pagination.php new file mode 100644 index 0000000..ba5ddc7 --- /dev/null +++ b/lang/vendor/filament/pt_BR/components/pagination.php @@ -0,0 +1,47 @@ + 'Paginação', + + 'overview' => '{1} Exibindo 1 resultado|[2,*] Exibindo :first a :last de :total resultados', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'por página', + + 'options' => [ + 'all' => 'Todas', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Primeira', + ], + + 'go_to_page' => [ + 'label' => 'Ir para página :page', + ], + + 'last' => [ + 'label' => 'Última', + ], + + 'next' => [ + 'label' => 'Próxima', + ], + + 'previous' => [ + 'label' => 'Anterior', + ], + + ], + +]; diff --git a/lang/vendor/filament/pt_PT/components/button.php b/lang/vendor/filament/pt_PT/components/button.php new file mode 100644 index 0000000..c54934d --- /dev/null +++ b/lang/vendor/filament/pt_PT/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'A carregar ficheiro...', + ], + +]; diff --git a/lang/vendor/filament/pt_PT/components/copyable.php b/lang/vendor/filament/pt_PT/components/copyable.php new file mode 100644 index 0000000..2aadb0b --- /dev/null +++ b/lang/vendor/filament/pt_PT/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copiado', + ], + +]; diff --git a/lang/vendor/filament/pt_PT/components/modal.php b/lang/vendor/filament/pt_PT/components/modal.php new file mode 100644 index 0000000..6759dad --- /dev/null +++ b/lang/vendor/filament/pt_PT/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Fechar', + ], + + ], + +]; diff --git a/lang/vendor/filament/pt_PT/components/pagination.php b/lang/vendor/filament/pt_PT/components/pagination.php new file mode 100644 index 0000000..5989b59 --- /dev/null +++ b/lang/vendor/filament/pt_PT/components/pagination.php @@ -0,0 +1,47 @@ + 'Paginação', + + 'overview' => '{1} A mostrar 1 resultado|[2,*] A mostrar :first a :last de :total resultados', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Por página', + + 'options' => [ + 'all' => 'Todos', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Primeira', + ], + + 'go_to_page' => [ + 'label' => 'Ir para a página :page', + ], + + 'last' => [ + 'label' => 'Última', + ], + + 'next' => [ + 'label' => 'Próxima', + ], + + 'previous' => [ + 'label' => 'Anterior', + ], + + ], + +]; diff --git a/lang/vendor/filament/ro/components/button.php b/lang/vendor/filament/ro/components/button.php new file mode 100644 index 0000000..d58a83f --- /dev/null +++ b/lang/vendor/filament/ro/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Se încarcă fișierul...', + ], + +]; diff --git a/lang/vendor/filament/ro/components/copyable.php b/lang/vendor/filament/ro/components/copyable.php new file mode 100644 index 0000000..4311f32 --- /dev/null +++ b/lang/vendor/filament/ro/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Copiat', + ], + +]; diff --git a/lang/vendor/filament/ro/components/modal.php b/lang/vendor/filament/ro/components/modal.php new file mode 100644 index 0000000..4d53d97 --- /dev/null +++ b/lang/vendor/filament/ro/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Închide', + ], + + ], + +]; diff --git a/lang/vendor/filament/ro/components/pagination.php b/lang/vendor/filament/ro/components/pagination.php new file mode 100644 index 0000000..090b9be --- /dev/null +++ b/lang/vendor/filament/ro/components/pagination.php @@ -0,0 +1,47 @@ + 'Navigare', + + 'overview' => 'Afișare :first-:last din :total rezultate', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Pe pagină', + + 'options' => [ + 'all' => 'Toate', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Prima pagină', + ], + + 'go_to_page' => [ + 'label' => 'Mergi la pagina :page', + ], + + 'last' => [ + 'label' => 'Ultima pagină', + ], + + 'next' => [ + 'label' => 'Pagina următoare', + ], + + 'previous' => [ + 'label' => 'Pagina precedentă', + ], + + ], + +]; diff --git a/lang/vendor/filament/ru/components/button.php b/lang/vendor/filament/ru/components/button.php new file mode 100644 index 0000000..f99b5d9 --- /dev/null +++ b/lang/vendor/filament/ru/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Загрузка файла...', + ], + +]; diff --git a/lang/vendor/filament/ru/components/copyable.php b/lang/vendor/filament/ru/components/copyable.php new file mode 100644 index 0000000..9bea728 --- /dev/null +++ b/lang/vendor/filament/ru/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Скопировано', + ], + +]; diff --git a/lang/vendor/filament/ru/components/modal.php b/lang/vendor/filament/ru/components/modal.php new file mode 100644 index 0000000..def7faf --- /dev/null +++ b/lang/vendor/filament/ru/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Закрыть', + ], + + ], + +]; diff --git a/lang/vendor/filament/ru/components/pagination.php b/lang/vendor/filament/ru/components/pagination.php new file mode 100644 index 0000000..3968468 --- /dev/null +++ b/lang/vendor/filament/ru/components/pagination.php @@ -0,0 +1,47 @@ + 'Пагинация', + + 'overview' => 'Показано с :first по :last из :total', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'на страницу', + + 'options' => [ + 'all' => 'Все', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Первая', + ], + + 'go_to_page' => [ + 'label' => 'Перейти к странице :page', + ], + + 'last' => [ + 'label' => 'Последняя', + ], + + 'next' => [ + 'label' => 'Следующая', + ], + + 'previous' => [ + 'label' => 'Предыдущая', + ], + + ], + +]; diff --git a/lang/vendor/filament/sk/components/button.php b/lang/vendor/filament/sk/components/button.php new file mode 100644 index 0000000..701b360 --- /dev/null +++ b/lang/vendor/filament/sk/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Nahrávam súbor...', + ], + +]; diff --git a/lang/vendor/filament/sk/components/copyable.php b/lang/vendor/filament/sk/components/copyable.php new file mode 100644 index 0000000..f41d39f --- /dev/null +++ b/lang/vendor/filament/sk/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Skopírované', + ], + +]; diff --git a/lang/vendor/filament/sk/components/modal.php b/lang/vendor/filament/sk/components/modal.php new file mode 100644 index 0000000..de79c90 --- /dev/null +++ b/lang/vendor/filament/sk/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Zavrieť', + ], + + ], + +]; diff --git a/lang/vendor/filament/sk/components/pagination.php b/lang/vendor/filament/sk/components/pagination.php new file mode 100644 index 0000000..3404ca5 --- /dev/null +++ b/lang/vendor/filament/sk/components/pagination.php @@ -0,0 +1,47 @@ + 'Stránkovanie', + + 'overview' => '{1} Zobrazuje sa jeden výsledok|[2,*] Zobrazuje sa :first až :last z celkových :total výsledkov', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Počet na stranu', + + 'options' => [ + 'all' => 'Všetky', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Prvá', + ], + + 'go_to_page' => [ + 'label' => 'Prejsť na stranu :page', + ], + + 'last' => [ + 'label' => 'Posledná', + ], + + 'next' => [ + 'label' => 'Ďalšia', + ], + + 'previous' => [ + 'label' => 'Predošlá', + ], + + ], + +]; diff --git a/lang/vendor/filament/sq/components/button.php b/lang/vendor/filament/sq/components/button.php new file mode 100644 index 0000000..18be013 --- /dev/null +++ b/lang/vendor/filament/sq/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Duke ngarkuar skedarin...', + ], + +]; diff --git a/lang/vendor/filament/sq/components/copyable.php b/lang/vendor/filament/sq/components/copyable.php new file mode 100644 index 0000000..c3461c8 --- /dev/null +++ b/lang/vendor/filament/sq/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'U kopjua', + ], + +]; diff --git a/lang/vendor/filament/sq/components/modal.php b/lang/vendor/filament/sq/components/modal.php new file mode 100644 index 0000000..6a8eca7 --- /dev/null +++ b/lang/vendor/filament/sq/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Mbyll', + ], + + ], + +]; diff --git a/lang/vendor/filament/sq/components/pagination.php b/lang/vendor/filament/sq/components/pagination.php new file mode 100644 index 0000000..afecb09 --- /dev/null +++ b/lang/vendor/filament/sq/components/pagination.php @@ -0,0 +1,39 @@ + 'Pagination navigation', + + 'overview' => '{1} Duke shfaqur 1 rezultat|[2,*] Duke shfaqur :first deri në :last rezultate nga :total ne total', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Për faqe', + + 'options' => [ + 'all' => 'Të gjithë', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Shko te faqja :page', + ], + + 'next' => [ + 'label' => 'Pasardhësi', + ], + + 'previous' => [ + 'label' => 'Paraardhësi', + ], + + ], + +]; diff --git a/lang/vendor/filament/sv/components/button.php b/lang/vendor/filament/sv/components/button.php new file mode 100644 index 0000000..0ed409f --- /dev/null +++ b/lang/vendor/filament/sv/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Laddar upp fil...', + ], + +]; diff --git a/lang/vendor/filament/sv/components/copyable.php b/lang/vendor/filament/sv/components/copyable.php new file mode 100644 index 0000000..5f53e48 --- /dev/null +++ b/lang/vendor/filament/sv/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopierades', + ], + +]; diff --git a/lang/vendor/filament/sv/components/modal.php b/lang/vendor/filament/sv/components/modal.php new file mode 100644 index 0000000..80ef73d --- /dev/null +++ b/lang/vendor/filament/sv/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Stäng', + ], + + ], + +]; diff --git a/lang/vendor/filament/sv/components/pagination.php b/lang/vendor/filament/sv/components/pagination.php new file mode 100644 index 0000000..2b96690 --- /dev/null +++ b/lang/vendor/filament/sv/components/pagination.php @@ -0,0 +1,47 @@ + 'Sidnavigering', + + 'overview' => '{1} Visar 1 resultat|[2,*] Visar :first till :last av :total resultat', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Per sida', + + 'options' => [ + 'all' => 'Alla', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Första', + ], + + 'go_to_page' => [ + 'label' => 'Gå till sida :page', + ], + + 'last' => [ + 'label' => 'Sista', + ], + + 'next' => [ + 'label' => 'Nästa', + ], + + 'previous' => [ + 'label' => 'Föregående', + ], + + ], + +]; diff --git a/lang/vendor/filament/sw/components/button.php b/lang/vendor/filament/sw/components/button.php new file mode 100644 index 0000000..bd5bc92 --- /dev/null +++ b/lang/vendor/filament/sw/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Inapakia faili...', + ], + +]; diff --git a/lang/vendor/filament/sw/components/copyable.php b/lang/vendor/filament/sw/components/copyable.php new file mode 100644 index 0000000..0ac96d5 --- /dev/null +++ b/lang/vendor/filament/sw/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Imeigwa', + ], + +]; diff --git a/lang/vendor/filament/sw/components/modal.php b/lang/vendor/filament/sw/components/modal.php new file mode 100644 index 0000000..71666e1 --- /dev/null +++ b/lang/vendor/filament/sw/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Funga', + ], + + ], + +]; diff --git a/lang/vendor/filament/sw/components/pagination.php b/lang/vendor/filament/sw/components/pagination.php new file mode 100644 index 0000000..50e231b --- /dev/null +++ b/lang/vendor/filament/sw/components/pagination.php @@ -0,0 +1,39 @@ + 'Urambazaji wa kurasa', + + 'overview' => 'Onesha :first mpaka :last ya :total ya matokeo', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'kwa kurasa', + + 'options' => [ + 'all' => 'Zote', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => 'Nenda kwenye kurasa :page', + ], + + 'next' => [ + 'label' => 'Mbele', + ], + + 'previous' => [ + 'label' => 'Nyuma', + ], + + ], + +]; diff --git a/lang/vendor/filament/th/components/button.php b/lang/vendor/filament/th/components/button.php new file mode 100644 index 0000000..30a0123 --- /dev/null +++ b/lang/vendor/filament/th/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'กำลังอัปโหลดไฟล์...', + ], + +]; diff --git a/lang/vendor/filament/th/components/copyable.php b/lang/vendor/filament/th/components/copyable.php new file mode 100644 index 0000000..073ea81 --- /dev/null +++ b/lang/vendor/filament/th/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'คัดลอกเรียบร้อย', + ], + +]; diff --git a/lang/vendor/filament/th/components/modal.php b/lang/vendor/filament/th/components/modal.php new file mode 100644 index 0000000..b30b173 --- /dev/null +++ b/lang/vendor/filament/th/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'ปิด', + ], + + ], + +]; diff --git a/lang/vendor/filament/th/components/pagination.php b/lang/vendor/filament/th/components/pagination.php new file mode 100644 index 0000000..8213579 --- /dev/null +++ b/lang/vendor/filament/th/components/pagination.php @@ -0,0 +1,47 @@ + 'การนำทางการแบ่งหน้า', + + 'overview' => '{1} แสดง 1 รายการ|[2,*] แสดง :first ถึง :last จาก :total รายการ', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'รายการต่อหน้า', + + 'options' => [ + 'all' => 'ทั้งหมด', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'หน้าแรก', + ], + + 'go_to_page' => [ + 'label' => 'ไปหน้า :page', + ], + + 'last' => [ + 'label' => 'หน้าสุดท้าย', + ], + + 'next' => [ + 'label' => 'ถัดไป', + ], + + 'previous' => [ + 'label' => 'หน้าก่อน', + ], + + ], + +]; diff --git a/lang/vendor/filament/tr/components/button.php b/lang/vendor/filament/tr/components/button.php new file mode 100644 index 0000000..a7ae994 --- /dev/null +++ b/lang/vendor/filament/tr/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Dosya yükleniyor...', + ], + +]; diff --git a/lang/vendor/filament/tr/components/copyable.php b/lang/vendor/filament/tr/components/copyable.php new file mode 100644 index 0000000..4b0c3ea --- /dev/null +++ b/lang/vendor/filament/tr/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Kopyalandı', + ], + +]; diff --git a/lang/vendor/filament/tr/components/modal.php b/lang/vendor/filament/tr/components/modal.php new file mode 100644 index 0000000..4af5ffb --- /dev/null +++ b/lang/vendor/filament/tr/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Kapat', + ], + + ], + +]; diff --git a/lang/vendor/filament/tr/components/pagination.php b/lang/vendor/filament/tr/components/pagination.php new file mode 100644 index 0000000..be2960c --- /dev/null +++ b/lang/vendor/filament/tr/components/pagination.php @@ -0,0 +1,37 @@ + 'Sayfalandırma Navigasyonu', + + 'overview' => 'Toplam :total sonuçtan :first ile :last arası görüntüleniyor', + + 'fields' => [ + + 'records_per_page' => [ + 'label' => 'sayfa başına', + + 'options' => [ + 'all' => 'Tümü', + ], + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => ':page. sayfaya git', + ], + + 'next' => [ + 'label' => 'Sonraki', + ], + + 'previous' => [ + 'label' => 'Önceki', + ], + + ], + +]; diff --git a/lang/vendor/filament/uk/components/button.php b/lang/vendor/filament/uk/components/button.php new file mode 100644 index 0000000..350ea6b --- /dev/null +++ b/lang/vendor/filament/uk/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Завантаження файлу...', + ], + +]; diff --git a/lang/vendor/filament/uk/components/copyable.php b/lang/vendor/filament/uk/components/copyable.php new file mode 100644 index 0000000..d4bd7b3 --- /dev/null +++ b/lang/vendor/filament/uk/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Скопійовано', + ], + +]; diff --git a/lang/vendor/filament/uk/components/modal.php b/lang/vendor/filament/uk/components/modal.php new file mode 100644 index 0000000..e03448b --- /dev/null +++ b/lang/vendor/filament/uk/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Закрити', + ], + + ], + +]; diff --git a/lang/vendor/filament/uk/components/pagination.php b/lang/vendor/filament/uk/components/pagination.php new file mode 100644 index 0000000..c71e82d --- /dev/null +++ b/lang/vendor/filament/uk/components/pagination.php @@ -0,0 +1,47 @@ + 'Пагінація', + + 'overview' => 'Показано з :first по :last з :total', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'на сторінку', + + 'options' => [ + 'all' => 'Всі', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Перша', + ], + + 'go_to_page' => [ + 'label' => 'Перейти до сторінки :page', + ], + + 'last' => [ + 'label' => 'Остання', + ], + + 'next' => [ + 'label' => 'Наступна', + ], + + 'previous' => [ + 'label' => 'Попередня', + ], + + ], + +]; diff --git a/lang/vendor/filament/uz/components/button.php b/lang/vendor/filament/uz/components/button.php new file mode 100644 index 0000000..36b1a2d --- /dev/null +++ b/lang/vendor/filament/uz/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Fayl yuklanmoqda...', + ], + +]; diff --git a/lang/vendor/filament/uz/components/copyable.php b/lang/vendor/filament/uz/components/copyable.php new file mode 100644 index 0000000..9277d5a --- /dev/null +++ b/lang/vendor/filament/uz/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Nusxalandi', + ], + +]; diff --git a/lang/vendor/filament/uz/components/modal.php b/lang/vendor/filament/uz/components/modal.php new file mode 100644 index 0000000..0c026cb --- /dev/null +++ b/lang/vendor/filament/uz/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Yopish', + ], + + ], + +]; diff --git a/lang/vendor/filament/uz/components/pagination.php b/lang/vendor/filament/uz/components/pagination.php new file mode 100644 index 0000000..e0709ed --- /dev/null +++ b/lang/vendor/filament/uz/components/pagination.php @@ -0,0 +1,39 @@ + 'Sahifalar navigatsiyasi', + + 'overview' => '{1} 1 natija ko\'rsatilmoqda |[2,*] :firstdan :lastgacha jami natijalar :totalta', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Har bir sahifaga', + + 'options' => [ + 'all' => 'Barchasi', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => ':pagechi sahifaga o\'tish', + ], + + 'next' => [ + 'label' => 'Keyingi', + ], + + 'previous' => [ + 'label' => 'Oldingi', + ], + + ], + +]; diff --git a/lang/vendor/filament/vi/components/button.php b/lang/vendor/filament/vi/components/button.php new file mode 100644 index 0000000..2a0183b --- /dev/null +++ b/lang/vendor/filament/vi/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => 'Đang tải tệp lên...', + ], + +]; diff --git a/lang/vendor/filament/vi/components/copyable.php b/lang/vendor/filament/vi/components/copyable.php new file mode 100644 index 0000000..baed251 --- /dev/null +++ b/lang/vendor/filament/vi/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => 'Đã sao chép', + ], + +]; diff --git a/lang/vendor/filament/vi/components/modal.php b/lang/vendor/filament/vi/components/modal.php new file mode 100644 index 0000000..968d15c --- /dev/null +++ b/lang/vendor/filament/vi/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => 'Đóng', + ], + + ], + +]; diff --git a/lang/vendor/filament/vi/components/pagination.php b/lang/vendor/filament/vi/components/pagination.php new file mode 100644 index 0000000..ec92087 --- /dev/null +++ b/lang/vendor/filament/vi/components/pagination.php @@ -0,0 +1,47 @@ + 'Điều hướng phân trang', + + 'overview' => '{1} Đang hiện 1 kết quả|[2,*] Đang hiện từ :first đến :last của :total kết quả', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => 'Mỗi trang', + + 'options' => [ + 'all' => 'Tất cả', + ], + + ], + + ], + + 'actions' => [ + + 'first' => [ + 'label' => 'Đầu tiên', + ], + + 'go_to_page' => [ + 'label' => 'Đi tới trang :page', + ], + + 'last' => [ + 'label' => 'Cuối cùng', + ], + + 'next' => [ + 'label' => 'Tiếp theo', + ], + + 'previous' => [ + 'label' => 'Trước đó', + ], + + ], + +]; diff --git a/lang/vendor/filament/zh_CN/components/button.php b/lang/vendor/filament/zh_CN/components/button.php new file mode 100644 index 0000000..ced2342 --- /dev/null +++ b/lang/vendor/filament/zh_CN/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => '文件上传中...', + ], + +]; diff --git a/lang/vendor/filament/zh_CN/components/copyable.php b/lang/vendor/filament/zh_CN/components/copyable.php new file mode 100644 index 0000000..309cf52 --- /dev/null +++ b/lang/vendor/filament/zh_CN/components/copyable.php @@ -0,0 +1,9 @@ + [ + 'copied' => '已复制', + ], + +]; diff --git a/lang/vendor/filament/zh_CN/components/modal.php b/lang/vendor/filament/zh_CN/components/modal.php new file mode 100644 index 0000000..ef0574a --- /dev/null +++ b/lang/vendor/filament/zh_CN/components/modal.php @@ -0,0 +1,13 @@ + [ + + 'close' => [ + 'label' => '关闭', + ], + + ], + +]; diff --git a/lang/vendor/filament/zh_CN/components/pagination.php b/lang/vendor/filament/zh_CN/components/pagination.php new file mode 100644 index 0000000..0848381 --- /dev/null +++ b/lang/vendor/filament/zh_CN/components/pagination.php @@ -0,0 +1,39 @@ + '分页', + + 'overview' => '{1} 只有 1 条记录|[2,*] 当前显示第 :first 条到第 :last 条,共 :total 条', + + 'fields' => [ + + 'records_per_page' => [ + + 'label' => '每页', + + 'options' => [ + 'all' => '所有', + ], + + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => '跳转到 :page', + ], + + 'next' => [ + 'label' => '下一页', + ], + + 'previous' => [ + 'label' => '上一页', + ], + + ], + +]; diff --git a/lang/vendor/filament/zh_TW/components/button.php b/lang/vendor/filament/zh_TW/components/button.php new file mode 100644 index 0000000..503e81a --- /dev/null +++ b/lang/vendor/filament/zh_TW/components/button.php @@ -0,0 +1,9 @@ + [ + 'uploading_file' => '正在上傳檔案...', + ], + +]; diff --git a/lang/vendor/filament/zh_TW/components/pagination.php b/lang/vendor/filament/zh_TW/components/pagination.php new file mode 100644 index 0000000..3eb2a50 --- /dev/null +++ b/lang/vendor/filament/zh_TW/components/pagination.php @@ -0,0 +1,33 @@ + '分頁導航', + + 'overview' => '正在顯示第 :first 至 :last 項結果,共 :total 項', + + 'fields' => [ + + 'records_per_page' => [ + 'label' => '每頁顯示', + ], + + ], + + 'actions' => [ + + 'go_to_page' => [ + 'label' => '前往第 :page 頁', + ], + + 'next' => [ + 'label' => '下一頁', + ], + + 'previous' => [ + 'label' => '上一頁', + ], + + ], + +]; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c484474 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2013 @@ +{ + "name": "admin-kyc", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@tailwindcss/vite": "^4.0.0", + "axios": "^1.7.4", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "tailwindcss": "^4.0.0", + "vite": "^6.0.11" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.36.0.tgz", + "integrity": "sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.36.0.tgz", + "integrity": "sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.36.0.tgz", + "integrity": "sha512-JQ1Jk5G4bGrD4pWJQzWsD8I1n1mgPXq33+/vP4sk8j/z/C2siRuxZtaUA7yMTf71TCZTZl/4e1bfzwUmFb3+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.36.0.tgz", + "integrity": "sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.36.0.tgz", + "integrity": "sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.36.0.tgz", + "integrity": "sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.36.0.tgz", + "integrity": "sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.36.0.tgz", + "integrity": "sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.36.0.tgz", + "integrity": "sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.36.0.tgz", + "integrity": "sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.36.0.tgz", + "integrity": "sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.36.0.tgz", + "integrity": "sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.36.0.tgz", + "integrity": "sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.36.0.tgz", + "integrity": "sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.36.0.tgz", + "integrity": "sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.36.0.tgz", + "integrity": "sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.36.0.tgz", + "integrity": "sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.36.0.tgz", + "integrity": "sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.36.0.tgz", + "integrity": "sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.15.tgz", + "integrity": "sha512-IODaJjNmiasfZX3IoS+4Em3iu0fD2HS0/tgrnkYfW4hyUor01Smnr5eY3jc4rRgaTDrJlDmBTHbFO0ETTDaxWA==", + "dev": true, + "dependencies": { + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "tailwindcss": "4.0.15" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.15.tgz", + "integrity": "sha512-e0uHrKfPu7JJGMfjwVNyt5M0u+OP8kUmhACwIRlM+JNBuReDVQ63yAD1NWe5DwJtdaHjugNBil76j+ks3zlk6g==", + "dev": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.0.15", + "@tailwindcss/oxide-darwin-arm64": "4.0.15", + "@tailwindcss/oxide-darwin-x64": "4.0.15", + "@tailwindcss/oxide-freebsd-x64": "4.0.15", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.15", + "@tailwindcss/oxide-linux-arm64-gnu": "4.0.15", + "@tailwindcss/oxide-linux-arm64-musl": "4.0.15", + "@tailwindcss/oxide-linux-x64-gnu": "4.0.15", + "@tailwindcss/oxide-linux-x64-musl": "4.0.15", + "@tailwindcss/oxide-win32-arm64-msvc": "4.0.15", + "@tailwindcss/oxide-win32-x64-msvc": "4.0.15" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.15.tgz", + "integrity": "sha512-EBuyfSKkom7N+CB3A+7c0m4+qzKuiN0WCvzPvj5ZoRu4NlQadg/mthc1tl5k9b5ffRGsbDvP4k21azU4VwVk3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.15.tgz", + "integrity": "sha512-ObVAnEpLepMhV9VoO0JSit66jiN5C4YCqW3TflsE9boo2Z7FIjV80RFbgeL2opBhtxbaNEDa6D0/hq/EP03kgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.15.tgz", + "integrity": "sha512-IElwoFhUinOr9MyKmGTPNi1Rwdh68JReFgYWibPWTGuevkHkLWKEflZc2jtI5lWZ5U9JjUnUfnY43I4fEXrc4g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.15.tgz", + "integrity": "sha512-6BLLqyx7SIYRBOnTZ8wgfXANLJV5TQd3PevRJZp0vn42eO58A2LykRKdvL1qyPfdpmEVtF+uVOEZ4QTMqDRAWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.15.tgz", + "integrity": "sha512-Zy63EVqO9241Pfg6G0IlRIWyY5vNcWrL5dd2WAKVJZRQVeolXEf1KfjkyeAAlErDj72cnyXObEZjMoPEKHpdNw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.15.tgz", + "integrity": "sha512-2NemGQeaTbtIp1Z2wyerbVEJZTkAWhMDOhhR5z/zJ75yMNf8yLnE+sAlyf6yGDNr+1RqvWrRhhCFt7i0CIxe4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.15.tgz", + "integrity": "sha512-342GVnhH/6PkVgKtEzvNVuQ4D+Q7B7qplvuH20Cfz9qEtydG6IQczTZ5IT4JPlh931MG1NUCVxg+CIorr1WJyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.15.tgz", + "integrity": "sha512-g76GxlKH124RuGqacCEFc2nbzRl7bBrlC8qDQMiUABkiifDRHOIUjgKbLNG4RuR9hQAD/MKsqZ7A8L08zsoBrw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.15.tgz", + "integrity": "sha512-Gg/Y1XrKEvKpq6WeNt2h8rMIKOBj/W3mNa5NMvkQgMC7iO0+UNLrYmt6zgZufht66HozNpn+tJMbbkZ5a3LczA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.15.tgz", + "integrity": "sha512-7QtSSJwYZ7ZK1phVgcNZpuf7c7gaCj8Wb0xjliligT5qCGCp79OV2n3SJummVZdw4fbTNKUOYMO7m1GinppZyA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.15.tgz", + "integrity": "sha512-JQ5H+5MLhOjpgNp6KomouE0ZuKmk3hO5h7/ClMNAQ8gZI2zkli3IH8ZqLbd2DVfXDbdxN2xvooIEeIlkIoSCqw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.15.tgz", + "integrity": "sha512-JRexava80NijI8cTcLXNM3nQL5A0ptTHI8oJLLe8z1MpNB6p5J4WCdJJP8RoyHu8/eB1JzEdbpH86eGfbuaezQ==", + "dev": true, + "dependencies": { + "@tailwindcss/node": "4.0.15", + "@tailwindcss/oxide": "4.0.15", + "lightningcss": "1.29.2", + "tailwindcss": "4.0.15" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/axios": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concurrently": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", + "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/laravel-vite-plugin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.2.0.tgz", + "integrity": "sha512-R0pJ+IcTVeqEMoKz/B2Ij57QVq3sFTABiFmb06gAwFdivbOgsUtuhX6N2MGLEArajrS3U5JbberzwOe7uXHMHQ==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "vite-plugin-full-reload": "^1.1.0" + }, + "bin": { + "clean-orphaned-assets": "bin/clean.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", + "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.29.2", + "lightningcss-darwin-x64": "1.29.2", + "lightningcss-freebsd-x64": "1.29.2", + "lightningcss-linux-arm-gnueabihf": "1.29.2", + "lightningcss-linux-arm64-gnu": "1.29.2", + "lightningcss-linux-arm64-musl": "1.29.2", + "lightningcss-linux-x64-gnu": "1.29.2", + "lightningcss-linux-x64-musl": "1.29.2", + "lightningcss-win32-arm64-msvc": "1.29.2", + "lightningcss-win32-x64-msvc": "1.29.2" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", + "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", + "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", + "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", + "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", + "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", + "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", + "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", + "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", + "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", + "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.36.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.36.0.tgz", + "integrity": "sha512-zwATAXNQxUcd40zgtQG0ZafcRK4g004WtEl7kbuhTWPvf07PsfohXl39jVUvPF7jvNAIkKPQ2XrsDlWuxBd++Q==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.36.0", + "@rollup/rollup-android-arm64": "4.36.0", + "@rollup/rollup-darwin-arm64": "4.36.0", + "@rollup/rollup-darwin-x64": "4.36.0", + "@rollup/rollup-freebsd-arm64": "4.36.0", + "@rollup/rollup-freebsd-x64": "4.36.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.36.0", + "@rollup/rollup-linux-arm-musleabihf": "4.36.0", + "@rollup/rollup-linux-arm64-gnu": "4.36.0", + "@rollup/rollup-linux-arm64-musl": "4.36.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.36.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.36.0", + "@rollup/rollup-linux-riscv64-gnu": "4.36.0", + "@rollup/rollup-linux-s390x-gnu": "4.36.0", + "@rollup/rollup-linux-x64-gnu": "4.36.0", + "@rollup/rollup-linux-x64-musl": "4.36.0", + "@rollup/rollup-win32-arm64-msvc": "4.36.0", + "@rollup/rollup-win32-ia32-msvc": "4.36.0", + "@rollup/rollup-win32-x64-msvc": "4.36.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tailwindcss": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.15.tgz", + "integrity": "sha512-6ZMg+hHdMJpjpeCCFasX7K+U615U9D+7k5/cDK/iRwl6GptF24+I/AbKgOnXhVKePzrEyIXutLv36n4cRsq3Sg==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/vite": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.2.tgz", + "integrity": "sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-full-reload": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", + "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "picomatch": "^2.3.1" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a047e26 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite" + }, + "devDependencies": { + "@tailwindcss/vite": "^4.0.0", + "axios": "^1.7.4", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "tailwindcss": "^4.0.0", + "vite": "^6.0.11" + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..506b9a3 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,33 @@ + +1?u.getGridIndex():u.getColIndex();e.dispatch("MOVE_ITEM",{query:o,index:f});let g=a.getIndex();if(g===void 0||g!==f){if(a.setIndex(f),g===void 0)return;e.dispatch("DID_REORDER_ITEMS",{items:e.query("GET_ACTIVE_ITEMS"),origin:r,target:f})}},vc=ge({DID_ADD_ITEM:hc,DID_REMOVE_ITEM:bc,DID_DRAG_ITEM:Ic}),xc=({root:e,props:t,actions:i,shouldOptimize:a})=>{vc({root:e,props:t,actions:i});let{dragCoordinates:n}=t,o=e.rect.element.width,l=e.childViews.filter(T=>T.rect.element.height),r=e.query("GET_ACTIVE_ITEMS").map(T=>l.find(v=>v.id===T.id)).filter(T=>T),s=n?Ji(e,r,n):null,p=e.ref.addIndex||null;e.ref.addIndex=null;let c=0,d=0,m=0;if(r.length===0)return;let u=r[0].rect.element,f=u.marginTop+u.marginBottom,g=u.marginLeft+u.marginRight,h=u.width+g,I=u.height+f,E=Ki(o,h);if(E===1){let T=0,v=0;r.forEach((y,b)=>{if(s){let _=b-s;_===-2?v=-f*.25:_===-1?v=-f*.75:_===0?v=f*.75:_===1?v=f*.25:v=0}a&&(y.translateX=null,y.translateY=null),y.markedForRemoval||ln(y,0,T+v);let x=(y.rect.element.height+f)*(y.markedForRemoval?y.opacity:1);T+=x})}else{let T=0,v=0;r.forEach((y,b)=>{b===s&&(c=1),b===p&&(m+=1),y.markedForRemoval&&y.opacity<.5&&(d-=1);let w=b+m+c+d,x=w%E,_=Math.floor(w/E),P=x*h,O=_*I,M=Math.sign(P-T),N=Math.sign(O-v);T=P,v=O,!y.markedForRemoval&&(a&&(y.translateX=null,y.translateY=null),ln(y,P,O,M,N))})}},yc=(e,t)=>t.filter(i=>i.data&&i.data.id?e.id===i.data.id:!0),_c=ne({create:gc,write:xc,tag:"ul",name:"list",didWriteView:({root:e})=>{e.childViews.filter(t=>t.markedForRemoval&&t.opacity===0&&t.resting).forEach(t=>{t._destroy(),e.removeChildView(t)})},filterFrameActionsForChild:yc,mixins:{apis:["dragCoordinates"]}}),Rc=({root:e,props:t})=>{e.ref.list=e.appendChildView(e.createChildView(_c)),t.dragCoordinates=null,t.overflowing=!1},wc=({root:e,props:t,action:i})=>{e.query("GET_ITEM_INSERT_LOCATION_FREEDOM")&&(t.dragCoordinates={left:i.position.scopeLeft-e.ref.list.rect.element.left,top:i.position.scopeTop-(e.rect.outer.top+e.rect.element.marginTop+e.rect.element.scrollTop)})},Sc=({props:e})=>{e.dragCoordinates=null},Lc=ge({DID_DRAG:wc,DID_END_DRAG:Sc}),Ac=({root:e,props:t,actions:i})=>{if(Lc({root:e,props:t,actions:i}),e.ref.list.dragCoordinates=t.dragCoordinates,t.overflowing&&!t.overflow&&(t.overflowing=!1,e.element.dataset.state="",e.height=null),t.overflow){let a=Math.round(t.overflow);a!==e.height&&(t.overflowing=!0,e.element.dataset.state="overflow",e.height=a)}},Mc=ne({create:Rc,write:Ac,name:"list-scroller",mixins:{apis:["overflow","dragCoordinates"],styles:["height","translateY"],animations:{translateY:"spring"}}}),Pe=(e,t,i,a="")=>{i?ce(e,t,a):e.removeAttribute(t)},Oc=e=>{if(!(!e||e.value==="")){try{e.value=""}catch{}if(e.value){let t=Ve("form"),i=e.parentNode,a=e.nextSibling;t.appendChild(e),t.reset(),a?i.insertBefore(e,a):i.appendChild(e)}}},Pc=({root:e,props:t})=>{e.element.id=`filepond--browser-${t.id}`,ce(e.element,"name",e.query("GET_NAME")),ce(e.element,"aria-controls",`filepond--assistant-${t.id}`),ce(e.element,"aria-labelledby",`filepond--drop-label-${t.id}`),Gn({root:e,action:{value:e.query("GET_ACCEPTED_FILE_TYPES")}}),Un({root:e,action:{value:e.query("GET_ALLOW_MULTIPLE")}}),Wn({root:e,action:{value:e.query("GET_ALLOW_DIRECTORIES_ONLY")}}),ki({root:e}),Hn({root:e,action:{value:e.query("GET_REQUIRED")}}),jn({root:e,action:{value:e.query("GET_CAPTURE_METHOD")}}),e.ref.handleChange=i=>{if(!e.element.value)return;let a=Array.from(e.element.files).map(n=>(n._relativePath=n.webkitRelativePath,n));setTimeout(()=>{t.onload(a),Oc(e.element)},250)},e.element.addEventListener("change",e.ref.handleChange)},Gn=({root:e,action:t})=>{e.query("GET_ALLOW_SYNC_ACCEPT_ATTRIBUTE")&&Pe(e.element,"accept",!!t.value,t.value?t.value.join(","):"")},Un=({root:e,action:t})=>{Pe(e.element,"multiple",t.value)},Wn=({root:e,action:t})=>{Pe(e.element,"webkitdirectory",t.value)},ki=({root:e})=>{let t=e.query("GET_DISABLED"),i=e.query("GET_ALLOW_BROWSE"),a=t||!i;Pe(e.element,"disabled",a)},Hn=({root:e,action:t})=>{t.value?e.query("GET_TOTAL_ITEMS")===0&&Pe(e.element,"required",!0):Pe(e.element,"required",!1)},jn=({root:e,action:t})=>{Pe(e.element,"capture",!!t.value,t.value===!0?"":t.value)},rn=({root:e})=>{let{element:t}=e;if(e.query("GET_TOTAL_ITEMS")>0){Pe(t,"required",!1),Pe(t,"name",!1);let i=e.query("GET_ACTIVE_ITEMS"),a=!1;for(let n=0;n