diff --git a/backend/Controllers/EquiposController.cs b/backend/Controllers/EquiposController.cs index 64db71e..6e16ba4 100644 --- a/backend/Controllers/EquiposController.cs +++ b/backend/Controllers/EquiposController.cs @@ -259,13 +259,125 @@ namespace Inventario.API.Controllers } [HttpPost("{hostname}/asociardiscos")] - public async Task AsociarDiscos(string hostname, [FromBody] List discos) + public async Task AsociarDiscos(string hostname, [FromBody] List discosDesdeCliente) { - // La lógica aquí es compleja, la implementaremos en un paso posterior si es necesaria. - // Por ahora, devolvemos un endpoint funcional pero que no hace nada. - Console.WriteLine($"Recibida solicitud para asociar {discos.Count} discos al equipo {hostname}"); - await Task.CompletedTask; // Simula trabajo asíncrono - return Ok(new { message = "Endpoint de asociación de discos recibido, lógica pendiente." }); + // 1. OBTENER EL EQUIPO + 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."); + } + + // Iniciar una transacción para asegurar que todas las operaciones se completen o ninguna lo haga. + using var transaction = connection.BeginTransaction(); + try + { + // 2. OBTENER ASOCIACIONES Y DISCOS ACTUALES DE LA BD + var discosActualesQuery = @" + SELECT d.Id, d.Mediatype, d.Size, ed.Id as EquipoDiscoId + FROM dbo.equipos_discos ed + JOIN dbo.discos d ON ed.disco_id = d.id + WHERE ed.equipo_id = @EquipoId;"; + + // Creamos una clase anónima temporal para mapear el resultado del JOIN + var discosEnDb = (await connection.QueryAsync(discosActualesQuery, new { EquipoId = equipo.Id }, transaction)).Select(d => new + { + Id = (int)d.Id, + Mediatype = (string)d.Mediatype, + Size = (int)d.Size, + EquipoDiscoId = (int)d.EquipoDiscoId + }).ToList(); + + // 3. AGRUPAR Y CONTAR DISCOS (del cliente y de la BD) + // Crea un diccionario estilo: {"SSD_256": 2, "HDD_1024": 1} + var discosClienteContados = discosDesdeCliente + .GroupBy(d => $"{d.Mediatype}_{d.Size}") + .ToDictionary(g => g.Key, g => g.Count()); + + var discosDbContados = discosEnDb + .GroupBy(d => $"{d.Mediatype}_{d.Size}") + .ToDictionary(g => g.Key, g => g.Count()); + + var cambios = new Dictionary(); + + // 4. CALCULAR Y EJECUTAR ELIMINACIONES + var discosAEliminar = new List(); + foreach (var discoDb in discosEnDb) + { + var key = $"{discoDb.Mediatype}_{discoDb.Size}"; + if (discosClienteContados.TryGetValue(key, out int count) && count > 0) + { + // Este disco todavía existe en el cliente, decrementamos el contador y lo saltamos. + discosClienteContados[key]--; + } + else + { + // Este disco ya no está en el cliente, marcamos su asociación para eliminar. + discosAEliminar.Add(discoDb.EquipoDiscoId); + + // Registrar para el historial + var nombreDisco = $"Disco {discoDb.Mediatype} {discoDb.Size}GB"; + var anterior = discosDbContados.GetValueOrDefault(key, 0); + if (!cambios.ContainsKey(nombreDisco)) cambios[nombreDisco] = (anterior.ToString(), (anterior - 1).ToString()); + else cambios[nombreDisco] = (anterior.ToString(), (int.Parse(cambios[nombreDisco].nuevo) - 1).ToString()); + } + } + if (discosAEliminar.Any()) + { + await connection.ExecuteAsync("DELETE FROM dbo.equipos_discos WHERE Id IN @Ids;", new { Ids = discosAEliminar }, transaction); + } + + // 5. CALCULAR Y EJECUTAR INSERCIONES + foreach (var discoCliente in discosDesdeCliente) + { + var key = $"{discoCliente.Mediatype}_{discoCliente.Size}"; + if (discosDbContados.TryGetValue(key, out int count) && count > 0) + { + // Este disco ya existía, decrementamos para no volver a añadirlo. + discosDbContados[key]--; + } + else + { + // Este es un disco nuevo que hay que asociar. + var disco = await connection.QuerySingleOrDefaultAsync("SELECT * FROM dbo.discos WHERE Mediatype = @Mediatype AND Size = @Size;", discoCliente, transaction); + if (disco == null) continue; // Si el disco no existe en la tabla maestra, lo ignoramos + + await connection.ExecuteAsync("INSERT INTO dbo.equipos_discos (equipo_id, disco_id) VALUES (@EquipoId, @DiscoId);", new { EquipoId = equipo.Id, DiscoId = disco.Id }, transaction); + + // Registrar para el historial + var nombreDisco = $"Disco {disco.Mediatype} {disco.Size}GB"; + var anterior = discosDbContados.GetValueOrDefault(key, 0); + if (!cambios.ContainsKey(nombreDisco)) cambios[nombreDisco] = (anterior.ToString(), (anterior + 1).ToString()); + else cambios[nombreDisco] = (anterior.ToString(), (int.Parse(cambios[nombreDisco].nuevo) + 1).ToString()); + } + } + + // 6. REGISTRAR CAMBIOS Y CONFIRMAR TRANSACCIÓN + if (cambios.Count > 0) + { + // Formateamos los valores para el historial + var cambiosFormateados = cambios.ToDictionary( + kvp => kvp.Key, + kvp => ($"{kvp.Value.anterior} Instalados", $"{kvp.Value.nuevo} Instalados") + ); + await HistorialHelper.RegistrarCambios(_context, equipo.Id, cambiosFormateados); + } + + transaction.Commit(); + + return Ok(new { message = "Discos sincronizados correctamente." }); + } + catch (Exception ex) + { + transaction.Rollback(); + // Loggear el error en el servidor + Console.WriteLine($"Error al asociar discos para {hostname}: {ex.Message}"); + return StatusCode(500, "Ocurrió un error interno al procesar la solicitud."); + } } [HttpPost("{hostname}/ram")] diff --git a/backend/obj/Debug/net9.0/Inventario.API.AssemblyInfo.cs b/backend/obj/Debug/net9.0/Inventario.API.AssemblyInfo.cs index 274d0e9..151a4cd 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+85bd1915e09fdb3a2af7e28d58b8ba794a9e6360")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+e14476ff8885fa0a5be99dba6f353b305f754677")] [assembly: System.Reflection.AssemblyProductAttribute("Inventario.API")] [assembly: System.Reflection.AssemblyTitleAttribute("Inventario.API")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]