187 lines
8.3 KiB
PHP
187 lines
8.3 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Resources\CompraResource\Pages;
|
|
|
|
use App\Filament\Resources\CompraResource;
|
|
use Filament\Actions;
|
|
use Filament\Resources\Pages\EditRecord;
|
|
use App\Models\Producto;
|
|
use App\Models\ProductVariant;
|
|
use App\Imports\CompraDetallesImport;
|
|
use App\Exports\PlantillaCompraExport;
|
|
use Maatwebsite\Excel\Facades\Excel;
|
|
use Filament\Forms\Components\FileUpload;
|
|
use Filament\Notifications\Notification;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class EditCompra extends EditRecord
|
|
{
|
|
protected static string $resource = CompraResource::class;
|
|
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Actions\Action::make('marcar_recibida')
|
|
->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;
|
|
}
|
|
}
|