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; } }