Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/classes/MsvcClassesApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
16 changes: 0 additions & 16 deletions src/main/java/com/classes/config/RestTemplateConfig.java

This file was deleted.

14 changes: 13 additions & 1 deletion src/main/java/com/classes/dtos/external/MemberInfoDTO.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.classes.dtos.external;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand All @@ -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;
}
3 changes: 1 addition & 2 deletions src/main/java/com/classes/entities/TrainerEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/com/classes/services/Impl/ClassStatsServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<MemberInfoDTO> 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<StudentInClassDTO> students = reservations.stream()
.map(reservation -> buildStudentDTO(reservation, membersInfo))
.collect(Collectors.toList());
Expand Down Expand Up @@ -115,14 +123,20 @@ private StudentInClassDTO buildStudentDTO(ClassReservation reservation, List<Mem
? (attendedClasses * 100.0 / totalClasses) : 0.0;

String initials = getInitials(memberInfo.getFirstName(), memberInfo.getLastName());

// Extraer tipo de membresía
String membershipType = "N/A";
if (memberInfo.getMembershipType() != null) {
membershipType = memberInfo.getMembershipType().getType();
}

return StudentInClassDTO.builder()
.memberId(reservation.getMemberId())
.name(memberInfo.getFirstName() + " " + memberInfo.getLastName())
.email(memberInfo.getEmail())
.avatarInitials(initials)
.status(memberInfo.getStatus())
.membershipType(memberInfo.getMembershipType())
.status(memberInfo.getStatus() != null ? memberInfo.getStatus() : "DESCONOCIDO")
.membershipType(membershipType)
.attendancePercentage(attendancePercentage)
.totalClasses((int) totalClasses)
.lastAccess(memberInfo.getLastAccess())
Expand Down Expand Up @@ -172,7 +186,7 @@ private MemberInfoDTO createDefaultMemberInfo(UUID memberId) {
.lastName("Desconocido")
.email("no-disponible@email.com")
.status("DESCONOCIDO")
.membershipType("N/A")
.membershipType(null) // membership es null por defecto
.build();
}

Expand Down
13 changes: 2 additions & 11 deletions src/main/java/com/classes/services/Impl/DashboardServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,34 @@ public class DashboardServiceImpl {
private final ClassReservationRepository reservationRepository;

public MemberDashboardDTO getDashboardForMember(UUID memberId) {
List<ClassReservation> reservations = reservationRepository.findByMemberId(memberId);

List<ClassReservation> reservations = reservationRepository.findByMemberId(memberId);
List<ClassReservation> 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());
LocalDateTime end = LocalDateTime.of(LocalDate.now(), r.getClassEntity().getEndTime());
return !now.isBefore(start) && !now.isAfter(end)
&& r.getStatus() == ReservationStatus.RESERVADO;
});

Optional<ClassReservation> nextClassOpt = activeReservations.stream()
.filter(r -> {
LocalDateTime start = LocalDateTime.of(LocalDate.now(), r.getClassEntity().getStartTime());
return start.isAfter(now);
})
.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<WeeklyActivityDTO> weeklyActivity = calcularActividadSemanal(activeReservations);

List<UpcomingClassDTO> upcoming = activeReservations.stream()
.filter(r -> {
LocalDateTime start = LocalDateTime.of(LocalDate.now(), r.getClassEntity().getStartTime());
Expand All @@ -75,7 +67,6 @@ public MemberDashboardDTO getDashboardForMember(UUID memberId) {
.location(r.getClassEntity().getLocation().getName())
.build())
.toList();

return MemberDashboardDTO.builder()
.inClass(inClass)
.remainingClasses(remaining)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<MemberInfoDTO> 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;
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/main/resources/bootstrap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 20MB
max-request-size: 20MB

# Logging para debuggear Feign
logging:
level:
com.classes.clients: DEBUG
feign: DEBUG
Loading