Skip to content

Commit a8c7fb2

Browse files
authored
Merge pull request #86 from chechojgb/buttonsLovers
refix: arreglar plano de PlanoAlmacen
2 parents ca0b0c3 + eccbc1d commit a8c7fb2

17 files changed

+731
-121
lines changed

app/Http/Controllers/BLInventarioController.php

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,44 @@ public function index()
2424
{
2525
$productos = BlProducto::with([
2626
'color',
27-
'empaques.inventarioDetalle.posicion.nivel.estanteria'
27+
'empaques.inventarioDetalle.zona.nivel.estanteria'
2828
])
2929
->get()
3030
->map(function ($producto) {
3131
// Obtener todas las ubicaciones donde está este producto
3232
$ubicaciones = [];
33+
$zonasUnicas = [];
34+
$estanteriasUnicas = []; // NUEVO: para almacenar códigos de estanterías
35+
3336
foreach ($producto->empaques as $empaque) {
3437
foreach ($empaque->inventarioDetalle as $inventario) {
35-
if ($inventario->posicion && $inventario->posicion->nivel && $inventario->posicion->nivel->estanteria) {
36-
$ubicaciones[] = $inventario->posicion->nivel->estanteria->nombre;
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;
3761
}
3862
}
3963
}
4064

41-
// Si no tiene ubicación, mostrar "Sin ubicación"
4265
$estanteria = !empty($ubicaciones) ? implode(', ', array_unique($ubicaciones)) : 'Sin ubicación';
4366

4467
return [
@@ -49,9 +72,14 @@ public function index()
4972
'descripcion' => $producto->descripcion,
5073
'stock_total' => $producto->empaques
5174
->where('estado', 'disponible')
52-
->sum('cantidad_unidades'),
75+
->sum('cantidad_por_empaque'),
5376
'estanteria' => $estanteria,
5477
'tiene_ubicacion' => !empty($ubicaciones),
78+
'ubicaciones_detalladas' => $zonasUnicas,
79+
'estanterias' => array_unique(array_column($zonasUnicas, 'estanteria_nombre')),
80+
'zonas_completas' => array_unique(array_column($zonasUnicas, 'codigo_completo')),
81+
// NUEVO: Array de códigos de estantería para el plano
82+
'estanterias_codigos' => array_unique($estanteriasUnicas),
5583
];
5684
});
5785

app/Models/BlInventarioDetalle.php

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@ class BlInventarioDetalle extends Model
1111

1212
protected $table = 'bl_inventario_detalle';
1313
protected $fillable = [
14-
'empaque_id', 'posicion_id', 'cantidad_actual',
15-
'fecha_ubicacion', 'fecha_vencimiento', 'estado', 'notas'
14+
'empaque_id',
15+
'zona_id', // Cambiado: posicion_id → zona_id
16+
'cantidad_actual',
17+
'fecha_ubicacion',
18+
'fecha_vencimiento',
19+
'estado',
20+
'notas'
1621
];
1722

1823
protected $dates = ['fecha_ubicacion', 'fecha_vencimiento'];
@@ -23,10 +28,10 @@ public function empaque()
2328
return $this->belongsTo(BlEmpaque::class, 'empaque_id');
2429
}
2530

26-
// Relación con posición
27-
public function posicion()
31+
// NUEVA RELACIÓN con zona (reemplaza posicion)
32+
public function zona()
2833
{
29-
return $this->belongsTo(BlPosicion::class, 'posicion_id');
34+
return $this->belongsTo(BlZonaNivel::class, 'zona_id');
3035
}
3136

3237
// Relación con producto (a través de empaque)
@@ -42,23 +47,43 @@ public function producto()
4247
);
4348
}
4449

45-
// Scopes útiles
50+
// Scopes útiles ACTUALIZADOS
4651
public function scopeDisponibles($query)
4752
{
4853
return $query->where('estado', 'disponible');
4954
}
5055

5156
public function scopeEnEstanteria($query, $estanteriaId)
5257
{
53-
return $query->whereHas('posicion.nivel.estanteria', function($q) use ($estanteriaId) {
58+
return $query->whereHas('zona.nivel.estanteria', function($q) use ($estanteriaId) {
5459
$q->where('id', $estanteriaId);
5560
});
5661
}
5762

63+
public function scopeEnZona($query, $zonaId)
64+
{
65+
return $query->where('zona_id', $zonaId);
66+
}
67+
5868
public function scopeConProducto($query, $productoId)
5969
{
6070
return $query->whereHas('empaque', function($q) use ($productoId) {
6171
$q->where('producto_id', $productoId);
6272
});
6373
}
74+
75+
// Nuevo scope para buscar por código de zona
76+
public function scopeEnZonaCodigo($query, $codigoZona)
77+
{
78+
return $query->whereHas('zona', function($q) use ($codigoZona) {
79+
$q->where('codigo_completo', $codigoZona);
80+
});
81+
}
82+
83+
// Scope para productos próximos a vencer
84+
public function scopeProximosAVencer($query, $dias = 30)
85+
{
86+
return $query->whereDate('fecha_vencimiento', '<=', now()->addDays($dias))
87+
->where('estado', 'disponible');
88+
}
6489
}

app/Models/BlZonaNivel.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use Illuminate\Database\Eloquent\Factories\HasFactory;
6+
use Illuminate\Database\Eloquent\Model;
7+
8+
class BlZonaNivel extends Model
9+
{
10+
use HasFactory;
11+
12+
protected $table = 'bl_zonas_nivel';
13+
protected $fillable = [
14+
'nivel_id',
15+
'zona',
16+
'codigo_completo',
17+
'capacidad_maxima',
18+
'productos_actuales',
19+
'descripcion',
20+
'activa'
21+
];
22+
23+
// Relación con nivel
24+
public function nivel()
25+
{
26+
return $this->belongsTo(BlNivelEstanteria::class, 'nivel_id');
27+
}
28+
29+
// Relación con inventario detalle
30+
public function inventarioDetalle()
31+
{
32+
return $this->hasMany(BlInventarioDetalle::class, 'zona_id');
33+
}
34+
35+
// Relación con estantería (a través de nivel)
36+
public function estanteria()
37+
{
38+
return $this->hasOneThrough(
39+
BlEstanteria::class,
40+
BlNivelEstanteria::class,
41+
'id', // Foreign key on bl_niveles_estanteria
42+
'id', // Foreign key on bl_estanterias
43+
'nivel_id', // Local key on bl_zonas_nivel
44+
'estanteria_id' // Local key on bl_niveles_estanteria
45+
);
46+
}
47+
48+
// Scope para zonas activas
49+
public function scopeActivas($query)
50+
{
51+
return $query->where('activa', true);
52+
}
53+
54+
// Scope para zonas con capacidad disponible
55+
public function scopeConCapacidad($query, $cantidad = 1)
56+
{
57+
return $query->whereRaw('(capacidad_maxima - productos_actuales) >= ?', [$cantidad]);
58+
}
59+
60+
// Método para calcular espacio disponible
61+
public function getEspacioDisponibleAttribute()
62+
{
63+
return $this->capacidad_maxima - $this->productos_actuales;
64+
}
65+
}

database/migrations/2025_09_24_180852_bl_estanterias_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ public function up(): void
3030
*/
3131
public function down(): void
3232
{
33-
//
33+
Schema::dropIfExists('bl_estanterias');
3434
}
3535
};

database/migrations/2025_09_24_180942_bl_niveles_estanteria_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ public function up(): void
3030
*/
3131
public function down(): void
3232
{
33-
//
33+
Schema::dropIfExists('bl_niveles_estanteria');
3434
}
3535
};

database/migrations/2025_09_24_181023_bl_posiciones_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ public function up(): void
3131
*/
3232
public function down(): void
3333
{
34-
//
34+
Schema::dropIfExists('bl_posiciones');
3535
}
3636
};

database/migrations/2025_09_24_181042_bl_inventario_detalle_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ public function up(): void
3232
*/
3333
public function down(): void
3434
{
35-
//
35+
Schema::dropIfExists('bl_inventario_detalle');
3636
}
3737
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up(): void
10+
{
11+
// Eliminar la tabla de manera segura
12+
Schema::dropIfExists('bl_posiciones');
13+
}
14+
15+
public function down(): void
16+
{
17+
// En caso de rollback, recrea la tabla si es necesario
18+
Schema::create('bl_posiciones', function (Blueprint $table) {
19+
$table->id();
20+
$table->foreignId('nivel_id')->constrained('bl_niveles_estanteria');
21+
$table->string('posicion');
22+
$table->string('codigo_completo')->unique();
23+
$table->decimal('ancho', 8, 2)->nullable();
24+
$table->decimal('alto', 8, 2)->nullable();
25+
$table->decimal('profundidad', 8, 2)->nullable();
26+
$table->integer('capacidad_maxima')->default(1);
27+
$table->boolean('ocupada')->default(false);
28+
$table->boolean('activa')->default(true);
29+
$table->timestamps();
30+
});
31+
}
32+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*/
12+
public function up(): void
13+
{
14+
Schema::create('bl_zonas_nivel', function (Blueprint $table) {
15+
$table->id();
16+
$table->foreignId('nivel_id')->constrained('bl_niveles_estanteria');
17+
$table->string('zona'); // 'A', 'B'
18+
$table->string('codigo_completo')->unique(); // Ej: 'RACK-01-B-A'
19+
$table->integer('capacidad_maxima')->default(5000); // mitad de la capacidad del nivel
20+
$table->integer('productos_actuales')->default(0);
21+
$table->text('descripcion')->nullable(); // "Frente", "Fondo", etc.
22+
$table->boolean('activa')->default(true);
23+
$table->timestamps();
24+
25+
$table->unique(['nivel_id', 'zona']);
26+
});
27+
}
28+
29+
/**
30+
* Reverse the migrations.
31+
*/
32+
public function down(): void
33+
{
34+
Schema::dropIfExists('bl_zonas_nivel');
35+
}
36+
};
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
use Illuminate\Support\Facades\DB;
7+
8+
return new class extends Migration
9+
{
10+
public function up(): void
11+
{
12+
// 1️⃣ Crear la nueva tabla temporal con la estructura correcta
13+
Schema::create('bl_inventario_detalle_new', function (Blueprint $table) {
14+
$table->id();
15+
$table->foreignId('empaque_id')->constrained('bl_empaques');
16+
$table->foreignId('zona_id')->constrained('bl_zonas_nivel'); // NUEVO CAMPO
17+
$table->integer('cantidad_actual')->default(0);
18+
$table->date('fecha_ubicacion');
19+
$table->date('fecha_vencimiento')->nullable();
20+
$table->enum('estado', ['disponible', 'reservado', 'danado', 'caducado'])->default('disponible');
21+
$table->text('notas')->nullable();
22+
$table->timestamps();
23+
24+
$table->unique(['empaque_id', 'zona_id']);
25+
$table->index(['zona_id', 'estado']);
26+
$table->index('fecha_vencimiento');
27+
});
28+
29+
// 2️⃣ Copiar los datos desde la tabla antigua
30+
// Aquí asumimos que existe un mapeo directo posicón_id → zona_id
31+
// Si necesitas un mapeo distinto, ajusta el SELECT
32+
DB::statement('
33+
INSERT INTO bl_inventario_detalle_new (id, empaque_id, zona_id, cantidad_actual, fecha_ubicacion, fecha_vencimiento, estado, notas, created_at, updated_at)
34+
SELECT id, empaque_id, posicion_id, cantidad_actual, fecha_ubicacion, fecha_vencimiento, estado, notas, created_at, updated_at
35+
FROM bl_inventario_detalle
36+
');
37+
38+
// 3️⃣ Eliminar la tabla antigua
39+
Schema::dropIfExists('bl_inventario_detalle');
40+
41+
// 4️⃣ Renombrar la nueva tabla con el nombre original
42+
Schema::rename('bl_inventario_detalle_new', 'bl_inventario_detalle');
43+
}
44+
45+
public function down(): void
46+
{
47+
// Revertir: volver a la tabla con posicion_id
48+
Schema::create('bl_inventario_detalle_old', function (Blueprint $table) {
49+
$table->id();
50+
$table->foreignId('empaque_id')->constrained('bl_empaques');
51+
$table->foreignId('posicion_id')->constrained('bl_posiciones');
52+
$table->integer('cantidad_actual')->default(0);
53+
$table->date('fecha_ubicacion');
54+
$table->date('fecha_vencimiento')->nullable();
55+
$table->enum('estado', ['disponible', 'reservado', 'danado', 'caducado'])->default('disponible');
56+
$table->text('notas')->nullable();
57+
$table->timestamps();
58+
59+
$table->unique(['empaque_id', 'posicion_id']);
60+
$table->index(['posicion_id', 'estado']);
61+
});
62+
63+
DB::statement('
64+
INSERT INTO bl_inventario_detalle_old (id, empaque_id, posicion_id, cantidad_actual, fecha_ubicacion, fecha_vencimiento, estado, notas, created_at, updated_at)
65+
SELECT id, empaque_id, zona_id, cantidad_actual, fecha_ubicacion, fecha_vencimiento, estado, notas, created_at, updated_at
66+
FROM bl_inventario_detalle
67+
');
68+
69+
Schema::dropIfExists('bl_inventario_detalle');
70+
Schema::rename('bl_inventario_detalle_old', 'bl_inventario_detalle');
71+
}
72+
};

0 commit comments

Comments
 (0)