diff --git a/build.gradle b/build.gradle index 3dfc6bd..a2570af 100644 --- a/build.gradle +++ b/build.gradle @@ -51,7 +51,7 @@ dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' compileOnly 'org.projectlombok:lombok' -// runtimeOnly 'com.mysql:mysql-connector-j' + runtimeOnly 'com.mysql:mysql-connector-j' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/src/main/java/com/example/moim/club/entity/Club.java b/src/main/java/com/example/moim/club/entity/Club.java index cd3d37f..4ff197c 100644 --- a/src/main/java/com/example/moim/club/entity/Club.java +++ b/src/main/java/com/example/moim/club/entity/Club.java @@ -8,6 +8,7 @@ import com.example.moim.global.exception.ResponseCode; import com.example.moim.global.util.file.model.FileInfo; import com.example.moim.match.entity.Match; +import com.example.moim.statistic.entity.Statistic; import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; @@ -85,6 +86,10 @@ public static Club from(ClubInput clubInput, FileInfo fileInfo) { club.mainUniformColor = clubInput.getMainUniformColor(); club.subUniformColor = clubInput.getSubUniformColor(); club.memberCount = 1; + + Statistic.createStatistic(club, SportsType.OVERALL); + Statistic.createStatistic(club, SportsType.FUTSAL); + Statistic.createStatistic(club, SportsType.SOCCER); return club; } diff --git a/src/main/java/com/example/moim/club/entity/UserClub.java b/src/main/java/com/example/moim/club/entity/UserClub.java index 7d11357..2f3096f 100644 --- a/src/main/java/com/example/moim/club/entity/UserClub.java +++ b/src/main/java/com/example/moim/club/entity/UserClub.java @@ -28,6 +28,8 @@ public class UserClub extends BaseEntity { private Integer scheduleCount; private Integer matchCount; + private int score; + public static UserClub createLeaderUserClub(User user, Club club) { UserClub userClub = new UserClub(); userClub.user = user; @@ -59,4 +61,8 @@ public static UserClub createUserClub(User user, Club club) { public void changeUserClub(ClubRole clubRole) { this.clubRole = clubRole; } + + public void updateScore(int score) { + this.score += score; + } } diff --git a/src/main/java/com/example/moim/global/enums/SportsType.java b/src/main/java/com/example/moim/global/enums/SportsType.java index d2ebd52..598ffff 100644 --- a/src/main/java/com/example/moim/global/enums/SportsType.java +++ b/src/main/java/com/example/moim/global/enums/SportsType.java @@ -4,7 +4,7 @@ import java.util.Optional; public enum SportsType { - SOCCER("축구"), FUTSAL("풋살"); + SOCCER("축구"), FUTSAL("풋살"), OVERALL("전체"); private final String koreanName; SportsType(String koreanName) { diff --git a/src/main/java/com/example/moim/global/exception/ResponseCode.java b/src/main/java/com/example/moim/global/exception/ResponseCode.java index da78e89..344d6db 100644 --- a/src/main/java/com/example/moim/global/exception/ResponseCode.java +++ b/src/main/java/com/example/moim/global/exception/ResponseCode.java @@ -40,10 +40,15 @@ public enum ResponseCode { MATCH_TIME_OUT(HttpStatus.BAD_REQUEST, "MATCH4007", "매치가 종료된 후 48시간이 지났습니다."), MATCH_NOT_CONFIRMED(HttpStatus.BAD_REQUEST, "MATCH4008", "확정된 매치가 아닙니다."), MATCH_SCHEDULE_NOT_FOUND(HttpStatus.BAD_REQUEST, "MATCH4009", "매치 일정이 확정되지 않았거나, 존재하지 않습니다."), + MATCH_DUPLICATED(HttpStatus.BAD_REQUEST, "MATCH4010", "해당 시간에 다른 매치가 존재합니다."), // MatchUser Error - MATCH_USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MATCH4005", "가입된 모임이 없습니다."), - MATCH_CANNOT_CANCEL(HttpStatus.BAD_REQUEST, "MATCH4006", "매치를 취소할 수 없습니다."), + MATCH_USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MATCHUSER4001", "가입된 모임이 없습니다."), + MATCH_CANNOT_CANCEL(HttpStatus.BAD_REQUEST, "MATCHUSER4002", "매치를 취소할 수 없습니다."), + MATCH_USER_NOT_ATTENDANCE(HttpStatus.BAD_REQUEST, "MATCHUSER4003", "매치에 참여한 클럽 소속이 아닙니다"), + + // Statistic Error + STATISTIC_NOT_FOUND(HttpStatus.NOT_FOUND, "STATISTIC4001", "전적을 찾을 수 없습니다."), // Token Error ACCESS_TOKEN_NOT_FOUND(HttpStatus.BAD_REQUEST, "TOKEN4001", "헤더에 토큰 값이 없습니다"), diff --git a/src/main/java/com/example/moim/match/entity/Match.java b/src/main/java/com/example/moim/match/entity/Match.java index a8e1ec6..d0ae2c5 100644 --- a/src/main/java/com/example/moim/match/entity/Match.java +++ b/src/main/java/com/example/moim/match/entity/Match.java @@ -165,7 +165,8 @@ public void setMatchScore(int homeScore, int awayScore) { public void timeDuplicationCheck(LocalDateTime startTime, LocalDateTime endTime) { if ((startTime.isBefore(this.startTime) && endTime.isBefore(this.startTime)) || (startTime.isAfter(this.endTime) && endTime.isAfter(this.endTime))) { - throw new MatchRecordExpireException("해당 시간대에 다른 매치 일정이 있습니다"); +// throw new MatchRecordExpireException("해당 시간대에 다른 매치 일정이 있습니다"); + throw new MatchControllerAdvice(ResponseCode.MATCH_DUPLICATED); } } } \ No newline at end of file diff --git a/src/main/java/com/example/moim/match/entity/MatchUser.java b/src/main/java/com/example/moim/match/entity/MatchUser.java index 89de4b6..2ac1eb3 100644 --- a/src/main/java/com/example/moim/match/entity/MatchUser.java +++ b/src/main/java/com/example/moim/match/entity/MatchUser.java @@ -1,9 +1,13 @@ package com.example.moim.match.entity; import com.example.moim.club.entity.Club; +import com.example.moim.global.exception.ResponseCode; +import com.example.moim.match.exception.advice.MatchControllerAdvice; +import com.example.moim.schedule.entity.ScheduleVote; import com.example.moim.schedule.vote.entity.ScheduleVote; import com.example.moim.club.entity.UserClub; import com.example.moim.match.dto.MatchRecordInput; +import com.example.moim.statistic.entity.Statistic; import com.example.moim.user.entity.User; import jakarta.persistence.*; import lombok.Getter; @@ -25,13 +29,16 @@ public class MatchUser { private Club club; private int score; + private String season; public static MatchUser createMatchUser(Match match, ScheduleVote scheduleVote) { MatchUser matchUser = new MatchUser(); matchUser.match = match; matchUser.user = scheduleVote.getUser(); - matchUser.club = findUserClubInMatch(match, scheduleVote.getUser()); + matchUser.club = scheduleVote.getSchedule().getClub(); +// matchUser.club = findUserClubInMatch(match, scheduleVote.getUser()); matchUser.score = 0; + matchUser.season = Statistic.getCurrentSeason(); return matchUser; } @@ -40,14 +47,17 @@ public void recordScore(MatchRecordInput matchRecordInput) { this.score = matchRecordInput.getScore(); } + // 이거 뭐지 private static Club findUserClubInMatch(Match match, User user) { for (UserClub userClub : user.getUserClub()) { Club myClub = userClub.getClub(); + if (myClub.equals(match.getHomeClub()) || myClub.equals(match.getAwayClub())) { return myClub; } } - throw new RuntimeException("해당 유저는 매치에 참여한 클럽 소속이 아닙니다."); +// throw new RuntimeException("해당 유저는 매치에 참여한 클럽 소속이 아닙니다."); + throw new MatchControllerAdvice(ResponseCode.MATCH_USER_NOT_ATTENDANCE); } } diff --git a/src/main/java/com/example/moim/match/service/MatchAggregateService.java b/src/main/java/com/example/moim/match/service/MatchAggregateService.java index 376e8a2..a6577a0 100644 --- a/src/main/java/com/example/moim/match/service/MatchAggregateService.java +++ b/src/main/java/com/example/moim/match/service/MatchAggregateService.java @@ -4,6 +4,7 @@ import com.example.moim.match.entity.MatchUser; import com.example.moim.match.repository.MatchRepository; import com.example.moim.match.repository.MatchUserRepository; +import com.example.moim.statistic.service.StatisticService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; @@ -19,6 +20,7 @@ public class MatchAggregateService { private final MatchRepository matchRepository; private final MatchUserRepository matchUserRepository; + private final StatisticService statisticService; //한시간마다 지금시간-48< 매치 끝나는시간 <지금시간이면 집계 @Scheduled(fixedRate = 1, timeUnit = TimeUnit.HOURS) @@ -43,6 +45,8 @@ public void aggregateMatchScore() { } log.info("Match ID: {}, homeScore: {}, awayScore: {}", match.getId(), homeScore, awayScore); match.setMatchScore(homeScore, awayScore); + + statisticService.updateStatistic(match); } } diff --git a/src/main/java/com/example/moim/statistic/controller/StatisticController.java b/src/main/java/com/example/moim/statistic/controller/StatisticController.java new file mode 100644 index 0000000..9a8ff02 --- /dev/null +++ b/src/main/java/com/example/moim/statistic/controller/StatisticController.java @@ -0,0 +1,21 @@ +package com.example.moim.statistic.controller; + +import com.example.moim.global.exception.BaseResponse; +import com.example.moim.global.exception.ResponseCode; +import com.example.moim.statistic.dto.StatisticDTO; +import com.example.moim.statistic.service.StatisticService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +public class StatisticController { + private StatisticService statisticService; + + // 전적 조회(전적 메인) + @GetMapping("/statistic/{clubId}") + public BaseResponse getStatistic(@PathVariable Long clubId, + @RequestBody StatisticDTO.StatisticInput request) { + return BaseResponse.onSuccess(statisticService.getStatistic(clubId, request.getTargetSeason(), request.getTargetType()), ResponseCode.OK); + } +} diff --git a/src/main/java/com/example/moim/statistic/dto/StatisticDTO.java b/src/main/java/com/example/moim/statistic/dto/StatisticDTO.java new file mode 100644 index 0000000..6cb7fba --- /dev/null +++ b/src/main/java/com/example/moim/statistic/dto/StatisticDTO.java @@ -0,0 +1,47 @@ +package com.example.moim.statistic.dto; + +import com.example.moim.statistic.entity.Statistic; +import lombok.AllArgsConstructor; +import lombok.Data; + +public class StatisticDTO { + @Data + @AllArgsConstructor + public static class StatisticInput { + private String targetSeason; + private String targetType; + } + + @Data + @AllArgsConstructor + public static class StatisticOutPut { + private String season; + private String rank; + private int point; + private float winRate; + private int winCount; + private int defeatCount; + private int drawCount; + private String mvpName; + private int mvpGoalCount; + + public StatisticOutPut(Statistic statistic) { + this.season = statistic.getSeason(); + this.point = statistic.getPoint(); + this.winRate = statistic.getWinRate(); + this.winCount = statistic.getWinCount(); + this.defeatCount = statistic.getDefeatCount(); + this.drawCount = statistic.getDrawCount(); + this.mvpName = statistic.getMvpName(); + this.mvpGoalCount = statistic.getMvpScore(); + this.rank = statistic.getTier().toString(); + } + } + + @Data + @AllArgsConstructor + public static class mvpDTO { + private String name; + private Long goalCount; + } +} diff --git a/src/main/java/com/example/moim/statistic/entity/Statistic.java b/src/main/java/com/example/moim/statistic/entity/Statistic.java new file mode 100644 index 0000000..26e071e --- /dev/null +++ b/src/main/java/com/example/moim/statistic/entity/Statistic.java @@ -0,0 +1,156 @@ +package com.example.moim.statistic.entity; + +import com.example.moim.club.entity.Club; +import com.example.moim.club.entity.UserClub; +import com.example.moim.global.entity.BaseEntity; +import com.example.moim.global.enums.SportsType; +import jakarta.persistence.*; +import lombok.Getter; + +import java.time.LocalDate; + +import static com.example.moim.statistic.entity.Tier.ROOKIE; + +@Entity +@Getter +public class Statistic extends BaseEntity { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JoinColumn(name = "club_id") + private Club club; + + private SportsType sportsType; + private String season; // -년 전반기 / 후반기 + private Tier tier; + private int point; + + private float winRate; // 소수점 한 자리 수까지 표기 + private int winCount; + private int drawCount; + private int defeatCount; + + private int winStreak; + private int defeatStreak; + + private int mvpScore; + private String mvpName; + + public static String getCurrentSeason() { + LocalDate now = LocalDate.now(); + int year = now.getYear(); + int month = now.getMonthValue(); + String half = (month <= 6) ? "상반기" : "하반기"; + + return year + " " + half + "전적"; + } + + // 모임 만들때 기본적으로 하나 생성, 반기별로 하나씩 생성 + public static Statistic createStatistic(Club club, SportsType sportsType) { + Statistic statistic = new Statistic(); + + statistic.club = club; + statistic.sportsType = sportsType; + statistic.season = Statistic.getCurrentSeason(); + statistic.tier = ROOKIE; + statistic.point = 305; + statistic.winRate = 0f; + statistic.winCount = 0; + statistic.drawCount = 0; + statistic.defeatCount = 0; + statistic.winStreak = 0; + statistic.defeatStreak = 0; + statistic.mvpScore = 0; + statistic.mvpName = null; + + return statistic; + } + + public void updateStatistic(int homeScore, int awayScore, int opponentRank, String mvpName, int mvpScore) { + int currentMatches = this.winCount + this.drawCount + this.defeatCount; // 배치고사 단계: 3경기 미만, 이후 경기부터는 정식 랭크 적용 + int pointsChange = 0; + + int ourRankLevel = this.tier.getLevel(); + int diff = opponentRank - ourRankLevel; + + if (homeScore > awayScore) { + this.winCount++; + this.winStreak += this.winStreak + 1; + this.defeatStreak = 0; + + if (this.tier == ROOKIE) { + pointsChange += 125; + } else { + pointsChange += 128; + // 3연승 이상이면 연승 보너스: 현재 연승 수 × 10점을 추가 + if (this.winStreak >= 3) { + pointsChange += this.winStreak * 10; + } + // 랭크 차이 보너스: 우리 팀의 랭크와 상대팀의 랭크 차이에 따라 추가 점수를 부여 + if (diff == 2) { + pointsChange += 100; + } else if (diff >= 3) { + pointsChange += 150; + } + } + } else if (homeScore < awayScore) { + this.defeatCount++; + this.defeatStreak += this.defeatStreak + 1; + this.winStreak = 0; + + if (this.tier == ROOKIE) { + pointsChange -= 75; + } else { + // 기본 패배 페널티는 -72점 + // 단, 연패 완화 로직: 3연패 시에는 -30점, 4연패 이상이면 페널티가 0점 + if (this.defeatStreak == 3) { + pointsChange += -30; + } else if (this.defeatStreak >= 4) { + pointsChange += 0; + } else { + pointsChange += -72; + } + } + } else { + this.drawCount++; + this.winStreak = 0; + this.defeatStreak = 0; + + if (this.tier == ROOKIE) { + pointsChange += 50; + } else { + pointsChange += 47; + } + } + + this.point += pointsChange; + + boolean isRookie = (currentMatches < 3); + if (!isRookie) { + if (this.point >= 1600) { + this.tier = Tier.M1; + } else if (this.point >= 1300) { + this.tier = Tier.M2; + } else if (this.point >= 875) { + this.tier = Tier.M3; + } else if (this.point >= 500) { + this.tier = Tier.M4; + } else { + this.tier = Tier.M5; + } + } + + this.mvpName = mvpName; + this.mvpScore = mvpScore; + + // 총 경기수 계산 후 승률 업데이트 (승률 = (승리수/총경기수)*100) + int totalMatches = this.winCount + this.drawCount + this.defeatCount; + this.winRate = totalMatches > 0 ? ((float) this.winCount / totalMatches) * 100 : 0; + } + + public void updateMvp(UserClub userClub) { + this.mvpName = userClub.getUser().getName(); + this.mvpScore = userClub.getScore(); + } +} diff --git a/src/main/java/com/example/moim/statistic/entity/Tier.java b/src/main/java/com/example/moim/statistic/entity/Tier.java new file mode 100644 index 0000000..0ddaf16 --- /dev/null +++ b/src/main/java/com/example/moim/statistic/entity/Tier.java @@ -0,0 +1,19 @@ +package com.example.moim.statistic.entity; + +import lombok.Getter; + +@Getter +public enum Tier { + M1(1), + M2(2), + M3(3), + M4(4), + M5(5), + ROOKIE(0); + + private final int level; + + Tier(int level) { + this.level = level; + } +} diff --git a/src/main/java/com/example/moim/statistic/exception/advice/StatisticControllerAdvice.java b/src/main/java/com/example/moim/statistic/exception/advice/StatisticControllerAdvice.java new file mode 100644 index 0000000..7153ead --- /dev/null +++ b/src/main/java/com/example/moim/statistic/exception/advice/StatisticControllerAdvice.java @@ -0,0 +1,12 @@ +package com.example.moim.statistic.exception.advice; + +import com.example.moim.global.exception.GeneralException; +import com.example.moim.global.exception.ResponseCode; + +public class StatisticControllerAdvice extends GeneralException { + + public StatisticControllerAdvice(ResponseCode responseCode) { + super(responseCode); + } + +} diff --git a/src/main/java/com/example/moim/statistic/repository/StatisticRepository.java b/src/main/java/com/example/moim/statistic/repository/StatisticRepository.java new file mode 100644 index 0000000..f76c498 --- /dev/null +++ b/src/main/java/com/example/moim/statistic/repository/StatisticRepository.java @@ -0,0 +1,47 @@ +package com.example.moim.statistic.repository; + +import com.example.moim.club.entity.Club; +import com.example.moim.global.enums.SportsType; +import com.example.moim.statistic.dto.StatisticDTO; +import com.example.moim.statistic.entity.Statistic; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface StatisticRepository extends JpaRepository { + // 현재 시즌 통합 mvp 유저 찾기(이름, 누적 점수) +// @Query(""" +// SELECT new com.example.moim.statistic.dto.StatisticDTO$mvpDTO(mu.user.name, SUM(mu.score)) +// FROM MatchUser mu +// WHERE mu.club = :club AND mu.season = :season +// GROUP BY mu.user +// ORDER BY SUM(mu.score) DESC +// """) +// List findTopScorerByClub(@Param("club") Club club, @Param("season") String season); + + // 현재 시즌 종목별 mvp 유저 찾기(이름, 누적 점수) + @Query(""" + SELECT new com.example.moim.statistic.dto.StatisticDTO$mvpDTO(mu.user.name, SUM(mu.score)) + FROM MatchUser mu + WHERE mu.club = :club + AND mu.season = :season + AND mu.match.event = :sportsType + GROUP BY mu.user + ORDER BY SUM(mu.score) DESC + """) + List findTopScorerByClubAndSportsType(@Param("club") Club club, + @Param("season") String season, + @Param("sportsType") SportsType sportsType); + + // 모임과 시즌으로 전적 찾기(통합) + Optional findByClubAndSeason(Club club, String season); + + // 종목별 시즌 전적 + Optional findByClubAndSeasonAndSportsType(Club club, String season, SportsType sportsType); +} diff --git a/src/main/java/com/example/moim/statistic/service/StatisticService.java b/src/main/java/com/example/moim/statistic/service/StatisticService.java new file mode 100644 index 0000000..51bd75a --- /dev/null +++ b/src/main/java/com/example/moim/statistic/service/StatisticService.java @@ -0,0 +1,128 @@ +package com.example.moim.statistic.service; + +import com.example.moim.club.entity.Club; +import com.example.moim.club.exception.advice.ClubControllerAdvice; +import com.example.moim.club.repository.ClubRepository; +import com.example.moim.global.enums.SportsType; +import com.example.moim.global.exception.ResponseCode; +import com.example.moim.match.entity.Match; +import com.example.moim.statistic.dto.StatisticDTO; +import com.example.moim.statistic.entity.Statistic; +import com.example.moim.statistic.exception.advice.StatisticControllerAdvice; +import com.example.moim.statistic.repository.StatisticRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class StatisticService { + private final StatisticRepository statisticRepository; + private final ClubRepository clubRepository; + + // 전적 생성(새로운 시즌) + // 매년 1월 1일과 7월 1일 + // 스케쥴 말고 배치 처리 고려해보기 + @Scheduled(cron = "0 0 0 1 1,7 ?") + @Transactional + public void createNewSeasonStatistics() { + String currentSeason = Statistic.getCurrentSeason(); + List clubs = clubRepository.findAll(); + + for (Club club : clubs) { + // 현재 시즌에 해당하는 Statistic이 존재하는지 확인하는 로직(통합, 풋살, 축구) + Optional existing = statisticRepository.findByClubAndSeasonAndSportsType(club, currentSeason, SportsType.OVERALL); + if (existing.isEmpty()) { + Statistic newStatistic = Statistic.createStatistic(club, SportsType.OVERALL); + Statistic newFulsalStatistic = Statistic.createStatistic(club, SportsType.FUTSAL); + Statistic newSoccerStatistic = Statistic.createStatistic(club, SportsType.SOCCER); + statisticRepository.save(newStatistic); + statisticRepository.save(newFulsalStatistic); + statisticRepository.save(newSoccerStatistic); + } + } + } + + // 전적 업데이트 로직 + public void updateStatistic(Match match) { + String currentSeason = Statistic.getCurrentSeason(); + + // 통합 + Statistic homeStatistic = statisticRepository.findByClubAndSeasonAndSportsType(match.getHomeClub(), currentSeason, SportsType.OVERALL) + .orElseThrow(() -> new StatisticControllerAdvice(ResponseCode.STATISTIC_NOT_FOUND)); + Statistic awayStatistic = statisticRepository.findByClubAndSeasonAndSportsType(match.getAwayClub(), currentSeason, SportsType.OVERALL) + .orElseThrow(() -> new StatisticControllerAdvice(ResponseCode.STATISTIC_NOT_FOUND)); + int homeRankLevel = homeStatistic.getTier().getLevel(); + int awayRankLevel = awayStatistic.getTier().getLevel(); + + StatisticDTO.mvpDTO homeMVPResult = statisticRepository + .findTopScorerByClubAndSportsType( + match.getHomeClub(), + currentSeason, + SportsType.OVERALL + ) + .stream() + .findFirst() + .orElse(new StatisticDTO.mvpDTO("No Data", 0L)); + + StatisticDTO.mvpDTO awayMVPResult = statisticRepository + .findTopScorerByClubAndSportsType( + match.getAwayClub(), + currentSeason, + SportsType.OVERALL + ) + .stream() + .findFirst() + .orElse(new StatisticDTO.mvpDTO("No Data", 0L)); + + homeStatistic.updateStatistic(match.getHomeScore(), match.getHomeScore(), homeRankLevel, homeMVPResult.getName(), homeMVPResult.getGoalCount().intValue()); + awayStatistic.updateStatistic(match.getAwayScore(), match.getAwayScore(), awayRankLevel, awayMVPResult.getName(), awayMVPResult.getGoalCount().intValue()); + + if (match.getEvent() == SportsType.FUTSAL) { + // 풋살 + Statistic homeFutsalStatistic = statisticRepository.findByClubAndSeasonAndSportsType(match.getHomeClub(), currentSeason, SportsType.FUTSAL) + .orElseThrow(); + Statistic awayFutsalStatistic = statisticRepository.findByClubAndSeasonAndSportsType(match.getAwayClub(), currentSeason, SportsType.FUTSAL) + .orElseThrow(); + int homeFutsalRankLevel = homeFutsalStatistic.getTier().getLevel(); + int awayFutsalRankLevel = awayFutsalStatistic.getTier().getLevel(); + + StatisticDTO.mvpDTO homeFutsalMVPResult = statisticRepository.findTopScorerByClubAndSportsType(match.getHomeClub(), currentSeason, SportsType.OVERALL).get(0); + StatisticDTO.mvpDTO awayFutsalMVPResult = statisticRepository.findTopScorerByClubAndSportsType(match.getHomeClub(), currentSeason, SportsType.OVERALL).get(0); + + homeFutsalStatistic.updateStatistic(match.getHomeScore(), match.getHomeScore(), homeFutsalRankLevel, homeMVPResult.getName(), homeFutsalMVPResult.getGoalCount().intValue()); + awayFutsalStatistic.updateStatistic(match.getAwayScore(), match.getAwayScore(), awayFutsalRankLevel, awayMVPResult.getName(), awayFutsalMVPResult.getGoalCount().intValue()); + } else if (match.getEvent() == SportsType.SOCCER) { + // 축구 + Statistic homeSoccerStatistic = statisticRepository.findByClubAndSeasonAndSportsType(match.getHomeClub(), currentSeason, SportsType.SOCCER) + .orElseThrow(); + Statistic awaySoccerStatistic = statisticRepository.findByClubAndSeasonAndSportsType(match.getAwayClub(), currentSeason, SportsType.SOCCER) + .orElseThrow(); + int homeSoccerRankLevel = homeSoccerStatistic.getTier().getLevel(); + int awaySoccerRankLevel = awaySoccerStatistic.getTier().getLevel(); + + StatisticDTO.mvpDTO homeSoccerMVPResult = statisticRepository.findTopScorerByClubAndSportsType(match.getHomeClub(), currentSeason, SportsType.OVERALL).get(0); + StatisticDTO.mvpDTO awaySoccerMVPResult = statisticRepository.findTopScorerByClubAndSportsType(match.getHomeClub(), currentSeason, SportsType.OVERALL).get(0); + + homeSoccerStatistic.updateStatistic(match.getHomeScore(), match.getAwayScore(), homeSoccerRankLevel, homeSoccerMVPResult.getName(), homeMVPResult.getGoalCount().intValue()); + awaySoccerStatistic.updateStatistic(match.getAwayScore(), match.getHomeScore(), awaySoccerRankLevel, awaySoccerMVPResult.getName(), awayMVPResult.getGoalCount().intValue()); + } + } + + // 전적 조회 + public StatisticDTO.StatisticOutPut getStatistic(Long clubId, String targetSeason, String sportsType) { +// String currentSeason = Statistic.getCurrentSeason(); + SportsType targetSportsType = SportsType.valueOf(sportsType); + Club club = clubRepository.findById(clubId) + .orElseThrow(() -> new ClubControllerAdvice(ResponseCode.CLUB_NOT_FOUND)); + Statistic statistic = statisticRepository.findByClubAndSeasonAndSportsType(club, targetSeason, targetSportsType) + .orElseThrow(() -> new StatisticControllerAdvice(ResponseCode.STATISTIC_NOT_FOUND)); + + return new StatisticDTO.StatisticOutPut(statistic); + } +} diff --git a/src/test/java/com/example/moim/match/MatchAggregateServiceTest.java b/src/test/java/com/example/moim/match/MatchAggregateServiceTest.java index 9260fca..e42716a 100644 --- a/src/test/java/com/example/moim/match/MatchAggregateServiceTest.java +++ b/src/test/java/com/example/moim/match/MatchAggregateServiceTest.java @@ -6,6 +6,7 @@ import com.example.moim.match.repository.MatchRepository; import com.example.moim.match.repository.MatchUserRepository; import com.example.moim.match.service.MatchAggregateService; +import com.example.moim.statistic.service.StatisticService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -30,6 +31,8 @@ class MatchAggregateServiceTest { private MatchRepository matchRepository; @Mock private MatchUserRepository matchUserRepository; + @Mock + private StatisticService statisticService; @InjectMocks private MatchAggregateService matchAggregateService;