diff --git a/pom.xml b/pom.xml index 20b332e..78a069d 100644 --- a/pom.xml +++ b/pom.xml @@ -62,6 +62,10 @@ org.springframework.cloud spring-cloud-starter-netflix-eureka-client + + org.springframework.cloud + spring-cloud-starter-openfeign + org.springframework.cloud spring-cloud-starter-bootstrap diff --git a/src/main/java/com/classes/MsvcClassesApplication.java b/src/main/java/com/classes/MsvcClassesApplication.java index fd1f000..cef39cd 100644 --- a/src/main/java/com/classes/MsvcClassesApplication.java +++ b/src/main/java/com/classes/MsvcClassesApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableFeignClients public class MsvcClassesApplication { public static void main(String[] args) { diff --git a/src/main/java/com/classes/config/RestTemplateConfig.java b/src/main/java/com/classes/config/RestTemplateConfig.java deleted file mode 100644 index a376e58..0000000 --- a/src/main/java/com/classes/config/RestTemplateConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.classes.config; - -import org.springframework.cloud.client.loadbalancer.LoadBalanced; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -@Configuration -public class RestTemplateConfig { - - @Bean - @LoadBalanced - public RestTemplate restTemplate() { - return new RestTemplate(); - } -} diff --git a/src/main/java/com/classes/dtos/external/MemberInfoDTO.java b/src/main/java/com/classes/dtos/external/MemberInfoDTO.java index 32fbed5..80eec96 100644 --- a/src/main/java/com/classes/dtos/external/MemberInfoDTO.java +++ b/src/main/java/com/classes/dtos/external/MemberInfoDTO.java @@ -1,5 +1,6 @@ package com.classes.dtos.external; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,17 +11,28 @@ /** * DTO para recibir información del microservicio de Members + * Mapea la respuesta de msvc-members con los nombres correctos de campos */ @Data @AllArgsConstructor @NoArgsConstructor @Builder public class MemberInfoDTO { + @JsonProperty("userId") // msvc-members usa "userId" private UUID id; + private String firstName; private String lastName; private String email; + private String dni; + private String phone; + private String initials; + private String profileImageUrl; + private String status; // "ACTIVO", "INACTIVO", "SUSPENDIDO" - private String membershipType; // "MENSUAL", "ANUAL", "PREMIUM" + + @JsonProperty("membership") // msvc-members usa "membership" + private MembershipDTO membershipType; + private LocalDateTime lastAccess; } diff --git a/src/main/java/com/classes/entities/TrainerEntity.java b/src/main/java/com/classes/entities/TrainerEntity.java index af4dcd9..e2c8d00 100644 --- a/src/main/java/com/classes/entities/TrainerEntity.java +++ b/src/main/java/com/classes/entities/TrainerEntity.java @@ -24,8 +24,7 @@ @EntityListeners(AuditListener.class) public class TrainerEntity { @Id - @GeneratedValue(strategy = GenerationType.UUID) - private UUID id; + private UUID id; // ID del usuario desde msvc-security (no se genera automáticamente) private String firstName; private String lastName; private String dni; diff --git a/src/main/java/com/classes/services/Impl/ClassStatsServiceImpl.java b/src/main/java/com/classes/services/Impl/ClassStatsServiceImpl.java index dcccf39..7aa2ab2 100644 --- a/src/main/java/com/classes/services/Impl/ClassStatsServiceImpl.java +++ b/src/main/java/com/classes/services/Impl/ClassStatsServiceImpl.java @@ -64,7 +64,15 @@ public ClassDetailResponse getClassDetail(UUID classId) { .map(ClassReservation::getMemberId) .distinct() .collect(Collectors.toList()); + + log.info("📋 Consultando información de {} miembros: {}", memberIds.size(), memberIds); List membersInfo = memberClientService.getMembersInfo(memberIds); + log.info("📊 Información obtenida de {} miembros", membersInfo.size()); + + if (membersInfo.isEmpty() && !memberIds.isEmpty()) { + log.warn("⚠️ No se pudo obtener información de ningún miembro. Usando datos por defecto."); + } + List students = reservations.stream() .map(reservation -> buildStudentDTO(reservation, membersInfo)) .collect(Collectors.toList()); @@ -115,14 +123,20 @@ private StudentInClassDTO buildStudentDTO(ClassReservation reservation, List reservations = reservationRepository.findByMemberId(memberId); + List reservations = reservationRepository.findByMemberId(memberId); List activeReservations = reservations.stream() .filter(r -> r.getStatus() == ReservationStatus.RESERVADO || Boolean.TRUE.equals(r.getAttended())) .toList(); - LocalDateTime now = LocalDateTime.now(); - boolean inClass = activeReservations.stream() .anyMatch(r -> { LocalDateTime start = LocalDateTime.of(LocalDate.now(), r.getClassEntity().getStartTime()); @@ -38,7 +36,6 @@ public MemberDashboardDTO getDashboardForMember(UUID memberId) { return !now.isBefore(start) && !now.isAfter(end) && r.getStatus() == ReservationStatus.RESERVADO; }); - Optional nextClassOpt = activeReservations.stream() .filter(r -> { LocalDateTime start = LocalDateTime.of(LocalDate.now(), r.getClassEntity().getStartTime()); @@ -46,19 +43,14 @@ public MemberDashboardDTO getDashboardForMember(UUID memberId) { }) .sorted(Comparator.comparing(r -> r.getClassEntity().getStartTime())) .findFirst(); - int totalReserved = (int) activeReservations.stream() - .filter(r -> r.getStatus() == ReservationStatus.RESERVADO) - .count(); - + .filter(r -> r.getStatus() == ReservationStatus.RESERVADO).count(); int attended = (int) activeReservations.stream() .filter(r -> Boolean.TRUE.equals(r.getAttended())) .count(); - int remaining = Math.max(totalReserved - attended, 0); int consecutiveDays = calcularDiasConsecutivos(activeReservations); List weeklyActivity = calcularActividadSemanal(activeReservations); - List upcoming = activeReservations.stream() .filter(r -> { LocalDateTime start = LocalDateTime.of(LocalDate.now(), r.getClassEntity().getStartTime()); @@ -75,7 +67,6 @@ public MemberDashboardDTO getDashboardForMember(UUID memberId) { .location(r.getClassEntity().getLocation().getName()) .build()) .toList(); - return MemberDashboardDTO.builder() .inClass(inClass) .remainingClasses(remaining) diff --git a/src/main/java/com/classes/services/Impl/MemberClientServiceImpl.java b/src/main/java/com/classes/services/Impl/MemberClientServiceImpl.java index 22cd230..fb3b2e6 100644 --- a/src/main/java/com/classes/services/Impl/MemberClientServiceImpl.java +++ b/src/main/java/com/classes/services/Impl/MemberClientServiceImpl.java @@ -1,15 +1,12 @@ package com.classes.services.Impl; +import com.classes.clients.MemberFeignClient; import com.classes.dtos.external.MemberInfoDTO; import com.classes.services.MemberClientService; +import feign.FeignException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.List; @@ -20,28 +17,26 @@ @Slf4j public class MemberClientServiceImpl implements MemberClientService { - private final RestTemplate restTemplate; - private static final String MEMBERS_SERVICE_URL = "http://msvc-members"; + private final MemberFeignClient memberFeignClient; @Override public MemberInfoDTO getMemberInfo(UUID memberId) { try { - String url = MEMBERS_SERVICE_URL + "/members/" + memberId; - log.debug("🔗 Llamando al microservicio de members: {}", url); - - ResponseEntity response = restTemplate.exchange( - url, - HttpMethod.GET, - null, - MemberInfoDTO.class - ); - return response.getBody(); - } catch (HttpClientErrorException.NotFound e) { - log.warn("❌ Miembro {} no encontrado en el microservicio de members", memberId); + log.info("🔗 Consultando información del miembro {} usando Feign", memberId); + MemberInfoDTO result = memberFeignClient.getMemberInfo(memberId); + log.info("✅ Información recibida: {} {}", result.getFirstName(), result.getLastName()); + return result; + } catch (FeignException.NotFound e) { + log.error("❌ Miembro {} no encontrado en msvc-members (404)", memberId); + return null; + } catch (FeignException e) { + log.error("❌ Error Feign al consultar miembro {}: {} - {}", + memberId, e.status(), e.getMessage()); + log.error("❌ Response body: {}", e.contentUTF8()); return null; } catch (Exception e) { - log.error("❌ Error al consultar el microservicio de members para el miembro {}: {}", - memberId, e.getMessage()); + log.error("❌ Error inesperado al consultar miembro {}: {}", + memberId, e.getMessage(), e); return null; } } diff --git a/src/main/resources/bootstrap.yml b/src/main/resources/bootstrap.yml index 3381ebb..5746442 100644 --- a/src/main/resources/bootstrap.yml +++ b/src/main/resources/bootstrap.yml @@ -9,4 +9,10 @@ spring: servlet: multipart: max-file-size: 10MB - max-request-size: 20MB \ No newline at end of file + max-request-size: 20MB + +# Logging para debuggear Feign +logging: + level: + com.classes.clients: DEBUG + feign: DEBUG \ No newline at end of file