Skip to content

Commit 0f09488

Browse files
author
chechojgb
committed
add: agregar productos BlNivelEstanteria
Se agrego un modal para agregar un producto a una estanteria o varias, se cambio el modelo al que apuntaban las estanterias de paquetes a productos como tal.
1 parent eccbc1d commit 0f09488

19 files changed

+636
-399
lines changed

app/Http/Controllers/BLInventarioController.php

Lines changed: 111 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
namespace App\Http\Controllers;
44

5-
use App\Models\BlEmpaque;
5+
66
use App\Models\BlEstanteria;
77
use App\Models\BlInventarioDetalle;
88
use App\Models\BlProducto;
99
use Illuminate\Http\Request;
1010
use Illuminate\Support\Facades\Auth;
1111
use Illuminate\Support\Facades\DB;
12+
use Illuminate\Support\Facades\Log;
1213
use Inertia\Inertia;
1314

1415
class BLInventarioController extends Controller
@@ -24,41 +25,37 @@ public function index()
2425
{
2526
$productos = BlProducto::with([
2627
'color',
27-
'empaques.inventarioDetalle.zona.nivel.estanteria'
28+
'inventarioDetalle.zona.nivel.estanteria' // ✅ Relación directa
2829
])
2930
->get()
3031
->map(function ($producto) {
3132
// Obtener todas las ubicaciones donde está este producto
3233
$ubicaciones = [];
3334
$zonasUnicas = [];
34-
$estanteriasUnicas = []; // NUEVO: para almacenar códigos de estanterías
35+
$estanteriasUnicas = [];
3536

36-
foreach ($producto->empaques as $empaque) {
37-
foreach ($empaque->inventarioDetalle as $inventario) {
38-
if ($inventario->zona && $inventario->zona->nivel && $inventario->zona->nivel->estanteria) {
39-
$estanteria = $inventario->zona->nivel->estanteria;
40-
$nivel = $inventario->zona->nivel;
41-
$zona = $inventario->zona;
42-
43-
// Crear ubicación legible
44-
$ubicacionLegible = $estanteria->nombre . ' - ' .
45-
$nivel->nivel . ' - ' .
46-
'Zona ' . $zona->zona;
47-
48-
$ubicaciones[] = $ubicacionLegible;
49-
50-
// Guardar información de zona única
51-
$zonasUnicas[] = [
52-
'estanteria_nombre' => $estanteria->nombre,
53-
'estanteria_codigo' => $estanteria->codigo, // EST-04, RACK-04, etc.
54-
'nivel_nombre' => $nivel->nivel,
55-
'zona_nombre' => $zona->zona,
56-
'codigo_completo' => $zona->codigo_completo
57-
];
58-
59-
// NUEVO: Guardar código de estantería para el plano
60-
$estanteriasUnicas[] = $estanteria->codigo;
61-
}
37+
// ✅ Ahora accedemos directamente desde el producto
38+
foreach ($producto->inventarioDetalle as $inventario) {
39+
if ($inventario->zona && $inventario->zona->nivel && $inventario->zona->nivel->estanteria) {
40+
$estanteria = $inventario->zona->nivel->estanteria;
41+
$nivel = $inventario->zona->nivel;
42+
$zona = $inventario->zona;
43+
44+
$ubicacionLegible = $estanteria->nombre . ' - ' .
45+
$nivel->nivel . ' - ' .
46+
'Zona ' . $zona->zona;
47+
48+
$ubicaciones[] = $ubicacionLegible;
49+
50+
$zonasUnicas[] = [
51+
'estanteria_nombre' => $estanteria->nombre,
52+
'estanteria_codigo' => $estanteria->codigo,
53+
'nivel_nombre' => $nivel->nivel,
54+
'zona_nombre' => $zona->zona,
55+
'codigo_completo' => $zona->codigo_completo
56+
];
57+
58+
$estanteriasUnicas[] = $estanteria->codigo;
6259
}
6360
}
6461

@@ -71,20 +68,101 @@ public function index()
7168
'color_nombre' => $producto->color->nombre,
7269
'descripcion' => $producto->descripcion,
7370
'stock_total' => $producto->empaques
74-
->where('estado', 'disponible')
75-
->sum('cantidad_por_empaque'),
71+
->where('estado', 'disponible')
72+
->sum('cantidad_por_empaque'),
7673
'estanteria' => $estanteria,
7774
'tiene_ubicacion' => !empty($ubicaciones),
7875
'ubicaciones_detalladas' => $zonasUnicas,
7976
'estanterias' => array_unique(array_column($zonasUnicas, 'estanteria_nombre')),
8077
'zonas_completas' => array_unique(array_column($zonasUnicas, 'codigo_completo')),
81-
// NUEVO: Array de códigos de estantería para el plano
8278
'estanterias_codigos' => array_unique($estanteriasUnicas),
8379
];
8480
});
8581

82+
$estanterias = BlEstanteria::with('niveles.zonaNivel.inventarioDetalle')->get();
8683
return Inertia::render('BLInventario', [
8784
'productos' => $productos,
85+
'estanterias' => $estanterias
8886
]);
8987
}
90-
}
88+
public function store(Request $request)
89+
{
90+
try {
91+
// Validar los datos recibidos
92+
$validated = $request->validate([
93+
'producto_id' => 'required|exists:bl_productos,id',
94+
'zona_id' => 'required|exists:bl_zonas_nivel,id',
95+
'cantidad_actual' => 'required|integer|min:1',
96+
'fecha_ubicacion' => 'required|date',
97+
'estado' => 'required|in:disponible,reservado,danado,caducado',
98+
]);
99+
100+
Log::info('Datos validados:', $validated);
101+
102+
// Buscar si ya existe el inventario en esa zona para ese producto
103+
$inventarioExistente = BlInventarioDetalle::where('producto_id', $validated['producto_id'])
104+
->where('zona_id', $validated['zona_id'])
105+
->first();
106+
107+
Log::info('Inventario existente:', [$inventarioExistente]);
108+
109+
if ($inventarioExistente) {
110+
$inventarioExistente->update([
111+
'cantidad_actual' => $validated['cantidad_actual'],
112+
'fecha_ubicacion' => $validated['fecha_ubicacion'],
113+
'estado' => $validated['estado'],
114+
'fecha_vencimiento' => $request->fecha_vencimiento,
115+
'notas' => $request->notas,
116+
]);
117+
118+
$mensaje = 'Ubicación actualizada correctamente';
119+
} else {
120+
// Crear nuevo inventario
121+
Log::info('Insertando inventario nuevo:', $validated);
122+
123+
BlInventarioDetalle::create([
124+
'producto_id' => $validated['producto_id'],
125+
'zona_id' => $validated['zona_id'],
126+
'cantidad_actual' => $validated['cantidad_actual'],
127+
'fecha_ubicacion' => $validated['fecha_ubicacion'],
128+
'fecha_vencimiento' => $request->fecha_vencimiento,
129+
'estado' => $validated['estado'],
130+
'notas' => $request->notas,
131+
]);
132+
133+
$mensaje = 'Producto ubicado correctamente en el almacén';
134+
}
135+
136+
// Actualizar contador de la zona
137+
$this->actualizarContadorZona($validated['zona_id']);
138+
139+
return redirect()->back()->with([
140+
'toast' => [
141+
'type' => 'success',
142+
'message' => $mensaje,
143+
],
144+
]);
145+
146+
} catch (\Exception $e) {
147+
Log::error('Error en store inventario:', [$e->getMessage()]);
148+
149+
return redirect()->back()->with([
150+
'toast' => [
151+
'type' => 'error',
152+
'message' => 'Error al guardar la ubicación: ' . $e->getMessage(),
153+
],
154+
]);
155+
}
156+
}
157+
158+
// Método auxiliar para actualizar el contador de la zona
159+
private function actualizarContadorZona($zonaId)
160+
{
161+
$totalProductos = BlInventarioDetalle::where('zona_id', $zonaId)
162+
->where('estado', 'disponible')
163+
->sum('cantidad_actual');
164+
DB::table('bl_zonas_nivel')
165+
->where('id', $zonaId)
166+
->update(['productos_actuales' => $totalProductos]);
167+
}
168+
}

app/Http/Controllers/BLMarcacionController.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Models\BLCliente;
66
use App\Models\BlMarcacion;
7+
use App\Models\BlMarcaciones;
78
use App\Models\BLPedido;
89
use App\Models\BLPedidoItem;
910
use App\Models\User;
@@ -48,7 +49,7 @@ public function store(Request $request)
4849
$data['costo_total'] = $data['cantidad'] * $data['precio_unitario'];
4950

5051
// 1️⃣ Guardar la marcación
51-
BlMarcacion::create($data);
52+
BlMarcaciones::create($data);
5253

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

6263
public function update(Request $request, $id)
6364
{
64-
$registro = BlMarcacion::findOrFail($id);
65+
$registro = BlMarcaciones::findOrFail($id);
6566

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

8081
public function destroy($id)
8182
{
82-
$registro = BlMarcacion::findOrFail($id);
83+
$registro = BlMarcaciones::findOrFail($id);
8384
$registro->delete();
8485

8586
return response()->json([

app/Http/Controllers/BlCuentaCobroController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function index()
1717
{
1818
// .producto
1919
$user = Auth::user();
20-
$cuentas = BlCuentaCobro::with(['itemsMarcacion.marcacion.pedido.items.empaque', 'usuario'])->get();
20+
$cuentas = BlCuentaCobro::with(['itemsMarcacion.marcacion.pedido.items.empaque.producto', 'usuario'])->get();
2121
return Inertia::render('BLCuentaCobro', [
2222
'user' => $user,
2323
'cuentasCobro' => $cuentas,

app/Models/BlEmpaque.php

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -39,52 +39,14 @@ public function pedidoItems(): HasMany
3939
{
4040
return $this->hasMany(BLPedidoItem::class, 'empaque_id');
4141
}
42-
public function inventarioDetalle()
43-
{
44-
return $this->hasMany(BlInventarioDetalle::class, 'empaque_id');
45-
}
4642

47-
// Relación directa con posiciones a través de inventario_detalle
48-
public function posiciones()
49-
{
50-
return $this->belongsToMany(BlPosicion::class, 'bl_inventario_detalle', 'empaque_id', 'posicion_id')
51-
->withPivot('cantidad_actual', 'estado', 'fecha_ubicacion')
52-
->withTimestamps();
53-
}
43+
5444

5545
// Scope para empaques disponibles
5646
public function scopeDisponibles($query)
5747
{
5848
return $query->where('estado', 'disponible');
5949
}
6050

61-
// Scope para empaques sin ubicación
62-
public function scopeSinUbicacion($query)
63-
{
64-
return $query->whereDoesntHave('inventarioDetalle');
65-
}
66-
67-
// Scope para empaques con ubicación
68-
public function scopeConUbicacion($query)
69-
{
70-
return $query->whereHas('inventarioDetalle');
71-
}
72-
73-
// Método para verificar si tiene ubicación
74-
public function getTieneUbicacionAttribute()
75-
{
76-
return $this->inventarioDetalle()->exists();
77-
}
7851

79-
// Método para obtener la ubicación actual (si tiene)
80-
public function getUbicacionActualAttribute()
81-
{
82-
return $this->inventarioDetalle()->first();
83-
}
84-
85-
// Método para obtener la cantidad total en inventario
86-
public function getCantidadEnInventarioAttribute()
87-
{
88-
return $this->inventarioDetalle()->sum('cantidad_actual');
89-
}
9052
}

app/Models/BlInventarioDetalle.php

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,32 @@ class BlInventarioDetalle extends Model
1010
use HasFactory;
1111

1212
protected $table = 'bl_inventario_detalle';
13+
1314
protected $fillable = [
14-
'empaque_id',
15-
'zona_id', // Cambiado: posicion_id → zona_id
16-
'cantidad_actual',
17-
'fecha_ubicacion',
18-
'fecha_vencimiento',
19-
'estado',
15+
'producto_id', // 🔄 antes era empaque_id
16+
'zona_id',
17+
'cantidad_actual',
18+
'fecha_ubicacion',
19+
'fecha_vencimiento',
20+
'estado',
2021
'notas'
2122
];
2223

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

25-
// Relación con empaque
26-
public function empaque()
26+
// Relación directa con producto (nuevo)
27+
public function producto()
2728
{
28-
return $this->belongsTo(BlEmpaque::class, 'empaque_id');
29+
return $this->belongsTo(BlProducto::class, 'producto_id');
2930
}
3031

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

37-
// Relación con producto (a través de empaque)
38-
public function producto()
39-
{
40-
return $this->hasOneThrough(
41-
BlProducto::class,
42-
BlEmpaque::class,
43-
'id', // Foreign key on bl_empaques table
44-
'id', // Foreign key on bl_productos table
45-
'empaque_id', // Local key on bl_inventario_detalle table
46-
'producto_id' // Local key on bl_empaques table
47-
);
48-
}
38+
// 🔥 Elimino la relación con empaque porque ya no aplica
4939

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

6858
public function scopeConProducto($query, $productoId)
6959
{
70-
return $query->whereHas('empaque', function($q) use ($productoId) {
71-
$q->where('producto_id', $productoId);
72-
});
60+
return $query->where('producto_id', $productoId);
7361
}
7462

7563
// Nuevo scope para buscar por código de zona
@@ -84,6 +72,6 @@ public function scopeEnZonaCodigo($query, $codigoZona)
8472
public function scopeProximosAVencer($query, $dias = 30)
8573
{
8674
return $query->whereDate('fecha_vencimiento', '<=', now()->addDays($dias))
87-
->where('estado', 'disponible');
75+
->where('estado', 'disponible');
8876
}
89-
}
77+
}

app/Models/BlNivelEstanteria.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ public function estanteria()
1919
}
2020

2121
// Relación con posiciones
22-
public function posiciones()
22+
public function zonaNivel()
2323
{
24-
return $this->hasMany(BlPosicion::class, 'nivel_id');
24+
return $this->hasMany(BlZonaNivel::class, 'nivel_id');
2525
}
2626

2727
// Relación con inventario detalle (a través de posiciones)

app/Models/BlProducto.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public function empaques(): HasMany
2323
return $this->hasMany(BlEmpaque::class, 'producto_id');
2424
}
2525

26+
// ✅ Relación DIRECTA con inventarioDetalle (usando producto_id)
27+
public function inventarioDetalle(): HasMany
28+
{
29+
return $this->hasMany(BlInventarioDetalle::class, 'producto_id');
30+
}
31+
2632
// Accesor: Descripción automática (ej: "BT 20MM Dorado")
2733
public function getDescripcionAttribute(): string
2834
{

0 commit comments

Comments
 (0)