Files
pos_heidiver/app/Filament/Pages/GestionStockPage.php
T
2026-01-06 15:35:59 -05:00

153 lines
5.6 KiB
PHP

<?php
namespace App\Filament\Pages;
use App\Models\Producto;
use App\Models\Bodega;
use Filament\Pages\Page;
use App\Services\TransferenciaBodegaService;
use Filament\Notifications\Notification;
class GestionStockPage extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-chart-bar-square';
protected static ?string $navigationLabel = 'Gestión de Stock';
protected static ?string $navigationGroup = 'Inventario';
protected static string $view = 'filament.pages.gestion-stock';
public $productosStockBajo;
public $bodegasEstado;
public $sugerenciasTransferencia;
public function mount(): void
{
// Datos para la vista
$this->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();
}
}
}