Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 111 additions & 33 deletions app/Http/Controllers/BLInventarioController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

namespace App\Http\Controllers;

use App\Models\BlEmpaque;

use App\Models\BlEstanteria;
use App\Models\BlInventarioDetalle;
use App\Models\BlProducto;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Inertia\Inertia;

class BLInventarioController extends Controller
Expand All @@ -24,41 +25,37 @@ public function index()
{
$productos = BlProducto::with([
'color',
'empaques.inventarioDetalle.zona.nivel.estanteria'
'inventarioDetalle.zona.nivel.estanteria' // ✅ Relación directa
])
->get()
->map(function ($producto) {
// Obtener todas las ubicaciones donde está este producto
$ubicaciones = [];
$zonasUnicas = [];
$estanteriasUnicas = []; // NUEVO: para almacenar códigos de estanterías
$estanteriasUnicas = [];

foreach ($producto->empaques as $empaque) {
foreach ($empaque->inventarioDetalle as $inventario) {
if ($inventario->zona && $inventario->zona->nivel && $inventario->zona->nivel->estanteria) {
$estanteria = $inventario->zona->nivel->estanteria;
$nivel = $inventario->zona->nivel;
$zona = $inventario->zona;

// Crear ubicación legible
$ubicacionLegible = $estanteria->nombre . ' - ' .
$nivel->nivel . ' - ' .
'Zona ' . $zona->zona;

$ubicaciones[] = $ubicacionLegible;

// Guardar información de zona única
$zonasUnicas[] = [
'estanteria_nombre' => $estanteria->nombre,
'estanteria_codigo' => $estanteria->codigo, // EST-04, RACK-04, etc.
'nivel_nombre' => $nivel->nivel,
'zona_nombre' => $zona->zona,
'codigo_completo' => $zona->codigo_completo
];

// NUEVO: Guardar código de estantería para el plano
$estanteriasUnicas[] = $estanteria->codigo;
}
// ✅ Ahora accedemos directamente desde el producto
foreach ($producto->inventarioDetalle as $inventario) {
if ($inventario->zona && $inventario->zona->nivel && $inventario->zona->nivel->estanteria) {
$estanteria = $inventario->zona->nivel->estanteria;
$nivel = $inventario->zona->nivel;
$zona = $inventario->zona;

$ubicacionLegible = $estanteria->nombre . ' - ' .
$nivel->nivel . ' - ' .
'Zona ' . $zona->zona;

$ubicaciones[] = $ubicacionLegible;

$zonasUnicas[] = [
'estanteria_nombre' => $estanteria->nombre,
'estanteria_codigo' => $estanteria->codigo,
'nivel_nombre' => $nivel->nivel,
'zona_nombre' => $zona->zona,
'codigo_completo' => $zona->codigo_completo
];

$estanteriasUnicas[] = $estanteria->codigo;
}
}

Expand All @@ -71,20 +68,101 @@ public function index()
'color_nombre' => $producto->color->nombre,
'descripcion' => $producto->descripcion,
'stock_total' => $producto->empaques
->where('estado', 'disponible')
->sum('cantidad_por_empaque'),
->where('estado', 'disponible')
->sum('cantidad_por_empaque'),
'estanteria' => $estanteria,
'tiene_ubicacion' => !empty($ubicaciones),
'ubicaciones_detalladas' => $zonasUnicas,
'estanterias' => array_unique(array_column($zonasUnicas, 'estanteria_nombre')),
'zonas_completas' => array_unique(array_column($zonasUnicas, 'codigo_completo')),
// NUEVO: Array de códigos de estantería para el plano
'estanterias_codigos' => array_unique($estanteriasUnicas),
];
});

$estanterias = BlEstanteria::with('niveles.zonaNivel.inventarioDetalle')->get();
return Inertia::render('BLInventario', [
'productos' => $productos,
'estanterias' => $estanterias
]);
}
}
public function store(Request $request)
{
try {
// Validar los datos recibidos
$validated = $request->validate([
'producto_id' => 'required|exists:bl_productos,id',
'zona_id' => 'required|exists:bl_zonas_nivel,id',
'cantidad_actual' => 'required|integer|min:1',
'fecha_ubicacion' => 'required|date',
'estado' => 'required|in:disponible,reservado,danado,caducado',
]);

Log::info('Datos validados:', $validated);

// Buscar si ya existe el inventario en esa zona para ese producto
$inventarioExistente = BlInventarioDetalle::where('producto_id', $validated['producto_id'])
->where('zona_id', $validated['zona_id'])
->first();

Log::info('Inventario existente:', [$inventarioExistente]);

if ($inventarioExistente) {
$inventarioExistente->update([
'cantidad_actual' => $validated['cantidad_actual'],
'fecha_ubicacion' => $validated['fecha_ubicacion'],
'estado' => $validated['estado'],
'fecha_vencimiento' => $request->fecha_vencimiento,
'notas' => $request->notas,
]);

$mensaje = 'Ubicación actualizada correctamente';
} else {
// Crear nuevo inventario
Log::info('Insertando inventario nuevo:', $validated);

BlInventarioDetalle::create([
'producto_id' => $validated['producto_id'],
'zona_id' => $validated['zona_id'],
'cantidad_actual' => $validated['cantidad_actual'],
'fecha_ubicacion' => $validated['fecha_ubicacion'],
'fecha_vencimiento' => $request->fecha_vencimiento,
'estado' => $validated['estado'],
'notas' => $request->notas,
]);

$mensaje = 'Producto ubicado correctamente en el almacén';
}

// Actualizar contador de la zona
$this->actualizarContadorZona($validated['zona_id']);

return redirect()->back()->with([
'toast' => [
'type' => 'success',
'message' => $mensaje,
],
]);

} catch (\Exception $e) {
Log::error('Error en store inventario:', [$e->getMessage()]);

return redirect()->back()->with([
'toast' => [
'type' => 'error',
'message' => 'Error al guardar la ubicación: ' . $e->getMessage(),
],
]);
}
}

// Método auxiliar para actualizar el contador de la zona
private function actualizarContadorZona($zonaId)
{
$totalProductos = BlInventarioDetalle::where('zona_id', $zonaId)
->where('estado', 'disponible')
->sum('cantidad_actual');
DB::table('bl_zonas_nivel')
->where('id', $zonaId)
->update(['productos_actuales' => $totalProductos]);
}
}
7 changes: 4 additions & 3 deletions app/Http/Controllers/BLMarcacionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use App\Models\BLCliente;
use App\Models\BlMarcacion;
use App\Models\BlMarcaciones;
use App\Models\BLPedido;
use App\Models\BLPedidoItem;
use App\Models\User;
Expand Down Expand Up @@ -48,7 +49,7 @@ public function store(Request $request)
$data['costo_total'] = $data['cantidad'] * $data['precio_unitario'];

// 1️⃣ Guardar la marcación
BlMarcacion::create($data);
BlMarcaciones::create($data);

// 2️⃣ Actualizar estado del item a "en_proceso"
DB::table('bl_pedido_items')
Expand All @@ -61,7 +62,7 @@ public function store(Request $request)

public function update(Request $request, $id)
{
$registro = BlMarcacion::findOrFail($id);
$registro = BlMarcaciones::findOrFail($id);

$request->validate([
'cantidad' => 'required|integer|min:1',
Expand All @@ -79,7 +80,7 @@ public function update(Request $request, $id)

public function destroy($id)
{
$registro = BlMarcacion::findOrFail($id);
$registro = BlMarcaciones::findOrFail($id);
$registro->delete();

return response()->json([
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/BlCuentaCobroController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function index()
{
// .producto
$user = Auth::user();
$cuentas = BlCuentaCobro::with(['itemsMarcacion.marcacion.pedido.items.empaque', 'usuario'])->get();
$cuentas = BlCuentaCobro::with(['itemsMarcacion.marcacion.pedido.items.empaque.producto', 'usuario'])->get();
return Inertia::render('BLCuentaCobro', [
'user' => $user,
'cuentasCobro' => $cuentas,
Expand Down
40 changes: 1 addition & 39 deletions app/Models/BlEmpaque.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,52 +39,14 @@ public function pedidoItems(): HasMany
{
return $this->hasMany(BLPedidoItem::class, 'empaque_id');
}
public function inventarioDetalle()
{
return $this->hasMany(BlInventarioDetalle::class, 'empaque_id');
}

// Relación directa con posiciones a través de inventario_detalle
public function posiciones()
{
return $this->belongsToMany(BlPosicion::class, 'bl_inventario_detalle', 'empaque_id', 'posicion_id')
->withPivot('cantidad_actual', 'estado', 'fecha_ubicacion')
->withTimestamps();
}


// Scope para empaques disponibles
public function scopeDisponibles($query)
{
return $query->where('estado', 'disponible');
}

// Scope para empaques sin ubicación
public function scopeSinUbicacion($query)
{
return $query->whereDoesntHave('inventarioDetalle');
}

// Scope para empaques con ubicación
public function scopeConUbicacion($query)
{
return $query->whereHas('inventarioDetalle');
}

// Método para verificar si tiene ubicación
public function getTieneUbicacionAttribute()
{
return $this->inventarioDetalle()->exists();
}

// Método para obtener la ubicación actual (si tiene)
public function getUbicacionActualAttribute()
{
return $this->inventarioDetalle()->first();
}

// Método para obtener la cantidad total en inventario
public function getCantidadEnInventarioAttribute()
{
return $this->inventarioDetalle()->sum('cantidad_actual');
}
}
42 changes: 15 additions & 27 deletions app/Models/BlInventarioDetalle.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,32 @@ class BlInventarioDetalle extends Model
use HasFactory;

protected $table = 'bl_inventario_detalle';

protected $fillable = [
'empaque_id',
'zona_id', // Cambiado: posicion_id → zona_id
'cantidad_actual',
'fecha_ubicacion',
'fecha_vencimiento',
'estado',
'producto_id', // 🔄 antes era empaque_id
'zona_id',
'cantidad_actual',
'fecha_ubicacion',
'fecha_vencimiento',
'estado',
'notas'
];

protected $dates = ['fecha_ubicacion', 'fecha_vencimiento'];

// Relación con empaque
public function empaque()
// Relación directa con producto (nuevo)
public function producto()
{
return $this->belongsTo(BlEmpaque::class, 'empaque_id');
return $this->belongsTo(BlProducto::class, 'producto_id');
}

// NUEVA RELACIÓN con zona (reemplaza posicion)
// Relación con zona (reemplaza posición)
public function zona()
{
return $this->belongsTo(BlZonaNivel::class, 'zona_id');
}

// Relación con producto (a través de empaque)
public function producto()
{
return $this->hasOneThrough(
BlProducto::class,
BlEmpaque::class,
'id', // Foreign key on bl_empaques table
'id', // Foreign key on bl_productos table
'empaque_id', // Local key on bl_inventario_detalle table
'producto_id' // Local key on bl_empaques table
);
}
// 🔥 Elimino la relación con empaque porque ya no aplica

// Scopes útiles ACTUALIZADOS
public function scopeDisponibles($query)
Expand All @@ -67,9 +57,7 @@ public function scopeEnZona($query, $zonaId)

public function scopeConProducto($query, $productoId)
{
return $query->whereHas('empaque', function($q) use ($productoId) {
$q->where('producto_id', $productoId);
});
return $query->where('producto_id', $productoId);
}

// Nuevo scope para buscar por código de zona
Expand All @@ -84,6 +72,6 @@ public function scopeEnZonaCodigo($query, $codigoZona)
public function scopeProximosAVencer($query, $dias = 30)
{
return $query->whereDate('fecha_vencimiento', '<=', now()->addDays($dias))
->where('estado', 'disponible');
->where('estado', 'disponible');
}
}
}
4 changes: 2 additions & 2 deletions app/Models/BlNivelEstanteria.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ public function estanteria()
}

// Relación con posiciones
public function posiciones()
public function zonaNivel()
{
return $this->hasMany(BlPosicion::class, 'nivel_id');
return $this->hasMany(BlZonaNivel::class, 'nivel_id');
}

// Relación con inventario detalle (a través de posiciones)
Expand Down
6 changes: 6 additions & 0 deletions app/Models/BlProducto.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ public function empaques(): HasMany
return $this->hasMany(BlEmpaque::class, 'producto_id');
}

// ✅ Relación DIRECTA con inventarioDetalle (usando producto_id)
public function inventarioDetalle(): HasMany
{
return $this->hasMany(BlInventarioDetalle::class, 'producto_id');
}

// Accesor: Descripción automática (ej: "BT 20MM Dorado")
public function getDescripcionAttribute(): string
{
Expand Down
Loading
Loading