From 99d98cc588b3922b6aa3ab9045fcee9cb31de1f3 Mon Sep 17 00:00:00 2001 From: dmolinari Date: Mon, 6 Oct 2025 14:59:39 -0300 Subject: [PATCH] =?UTF-8?q?feat:=20Implementa=20l=C3=B3gica=20completa=20d?= =?UTF-8?q?e=20sincronizaci=C3=B3n=20de=20RAM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/Controllers/EquiposController.cs | 89 +++++++++++++++++-- .../net9.0/Inventario.API.AssemblyInfo.cs | 2 +- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/backend/Controllers/EquiposController.cs b/backend/Controllers/EquiposController.cs index 6e16ba4..0f0a3ed 100644 --- a/backend/Controllers/EquiposController.cs +++ b/backend/Controllers/EquiposController.cs @@ -381,12 +381,91 @@ namespace Inventario.API.Controllers } [HttpPost("{hostname}/ram")] - public async Task AsociarRam(string hostname, [FromBody] List memorias) + public async Task AsociarRam(string hostname, [FromBody] List memoriasDesdeCliente) { - // Lógica compleja, pendiente de implementación. - Console.WriteLine($"Recibida solicitud para asociar {memorias.Count} módulos de RAM al equipo {hostname}"); - await Task.CompletedTask; - return Ok(new { message = "Endpoint de asociación de RAM recibido, lógica pendiente." }); + var equipoQuery = "SELECT * FROM dbo.equipos WHERE Hostname = @Hostname;"; + using var connection = _context.CreateConnection(); + connection.Open(); + var equipo = await connection.QuerySingleOrDefaultAsync(equipoQuery, new { Hostname = hostname }); + + if (equipo == null) + { + return NotFound("Equipo no encontrado."); + } + + using var transaction = connection.BeginTransaction(); + try + { + // 1. OBTENER ASOCIACIONES DE RAM ACTUALES + var ramActualQuery = @" + SELECT emr.Id as EquipoMemoriaRamId, emr.Slot, mr.Id, mr.part_number as PartNumber, mr.Fabricante, mr.Tamano, mr.Velocidad + FROM dbo.equipos_memorias_ram emr + JOIN dbo.memorias_ram mr ON emr.memoria_ram_id = mr.id + WHERE emr.equipo_id = @EquipoId;"; + + var ramEnDb = (await connection.QueryAsync(ramActualQuery, new { EquipoId = equipo.Id }, transaction)).ToList(); + + // 2. CREAR "HUELLAS DIGITALES" ÚNICAS PARA COMPARAR + // Una huella única para cada módulo en un slot. Ej: "DIMM0_Kingston_8_3200" + Func crearHuella = ram => + $"{ram.Slot}_{ram.PartNumber ?? ""}_{ram.Tamano}_{ram.Velocidad ?? 0}"; + + var huellasCliente = new HashSet(memoriasDesdeCliente.Select(crearHuella)); + var huellasDb = new HashSet(ramEnDb.Select(crearHuella)); + + // 3. CALCULAR Y EJECUTAR ELIMINACIONES + var asociacionesAEliminar = ramEnDb + .Where(ramDb => !huellasCliente.Contains(crearHuella(ramDb))) + .Select(ramDb => (int)ramDb.EquipoMemoriaRamId) + .ToList(); + + if (asociacionesAEliminar.Any()) + { + await connection.ExecuteAsync("DELETE FROM dbo.equipos_memorias_ram WHERE Id IN @Ids;", new { Ids = asociacionesAEliminar }, transaction); + } + + // 4. CALCULAR Y EJECUTAR INSERCIONES + var memoriasAInsertar = memoriasDesdeCliente.Where(ramCliente => !huellasDb.Contains(crearHuella(ramCliente))).ToList(); + + foreach (var memInfo in memoriasAInsertar) + { + // Buscar o crear el módulo de RAM en la tabla maestra 'memorias_ram' + var findRamQuery = @"SELECT * FROM dbo.memorias_ram WHERE + (part_number = @PartNumber OR (part_number IS NULL AND @PartNumber IS NULL)) AND + tamano = @Tamano AND (velocidad = @Velocidad OR (velocidad IS NULL AND @Velocidad IS NULL));"; + + var memoriaMaestra = await connection.QuerySingleOrDefaultAsync(findRamQuery, memInfo, transaction); + + int memoriaMaestraId; + if (memoriaMaestra == null) + { + var insertRamQuery = @"INSERT INTO dbo.memorias_ram (part_number, fabricante, tamano, velocidad) + VALUES (@PartNumber, @Fabricante, @Tamano, @Velocidad); + SELECT CAST(SCOPE_IDENTITY() as int);"; + memoriaMaestraId = await connection.ExecuteScalarAsync(insertRamQuery, memInfo, transaction); + } + else + { + memoriaMaestraId = memoriaMaestra.Id; + } + + // Crear la asociación en la tabla intermedia + var insertAsociacionQuery = "INSERT INTO dbo.equipos_memorias_ram (equipo_id, memoria_ram_id, slot) VALUES (@EquipoId, @MemoriaRamId, @Slot);"; + await connection.ExecuteAsync(insertAsociacionQuery, new { EquipoId = equipo.Id, MemoriaRamId = memoriaMaestraId, memInfo.Slot }, transaction); + } + + // (Opcional, pero recomendado) Registrar cambios en el historial. + // La lógica exacta para el historial de RAM puede ser compleja y la omitimos por ahora para centrarnos en la sincronización. + + transaction.Commit(); + return Ok(new { message = "Módulos de RAM sincronizados correctamente." }); + } + catch (Exception ex) + { + transaction.Rollback(); + Console.WriteLine($"Error al asociar RAM para {hostname}: {ex.Message}"); + return StatusCode(500, "Ocurrió un error interno al procesar la solicitud de RAM."); + } } [HttpPost("ping")] diff --git a/backend/obj/Debug/net9.0/Inventario.API.AssemblyInfo.cs b/backend/obj/Debug/net9.0/Inventario.API.AssemblyInfo.cs index 151a4cd..67654b2 100644 --- a/backend/obj/Debug/net9.0/Inventario.API.AssemblyInfo.cs +++ b/backend/obj/Debug/net9.0/Inventario.API.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("Inventario.API")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+e14476ff8885fa0a5be99dba6f353b305f754677")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3fbc9abf584ee687cb8cd7cea9ab20b716bdd897")] [assembly: System.Reflection.AssemblyProductAttribute("Inventario.API")] [assembly: System.Reflection.AssemblyTitleAttribute("Inventario.API")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]