Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ SecurityFilterChain authenticated(HttpSecurity httpSecurity) throws Exception {
requests
.requestMatchers(HttpMethod.PUT, "/api/members/{memberId}/department")
.hasAnyRole(ADMIN);
requests.requestMatchers(HttpMethod.GET, "/api/attend/statistic").hasAnyRole(ADMIN);
requests.anyRequest().authenticated();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class SemesterPeriodController {
return ApiResponseGenerator.success(response, HttpStatus.CREATED, MessageCode.CREATE);
}

@GetMapping("/semester-periods")
@GetMapping("/admin/semester-periods")
public ApiResponse<ApiResponseBody.SuccessBody<SemesterPeriodApplicationQuery>>
getSemesterPeriod() {
SemesterPeriodApplicationQuery response = getSemesterPeriodUsecase.getSemesterPeriod();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.blackcompany.eeos.target.application.dto;

import com.blackcompany.eeos.common.support.dto.AbstractResponseDto;
import java.util.List;

public record AttendStatisticsResponse(List<MemberStatistics> members)
implements AbstractResponseDto {

public record MemberStatistics(
Long id,
String name,
String activeStatus,
int lateCount,
int absentCount,
int penaltyPoint) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.blackcompany.eeos.common.application.model.MemberIdModel;
import com.blackcompany.eeos.common.support.AbstractModel;
import com.blackcompany.eeos.target.persistence.TeamBuildingInputStatus;
import com.blackcompany.eeos.target.persistence.teambuilding.TeamBuildingInputStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import com.blackcompany.eeos.common.support.converter.AbstractEntityConverter;
import com.blackcompany.eeos.target.application.model.TeamBuildingTargetModel;
import com.blackcompany.eeos.target.persistence.TeamBuildingInputDataEntity;
import com.blackcompany.eeos.target.persistence.TeamBuildingInputStatus;
import com.blackcompany.eeos.target.persistence.TeamBuildingTargetEntity;
import com.blackcompany.eeos.target.persistence.teambuilding.TeamBuildingInputDataEntity;
import com.blackcompany.eeos.target.persistence.teambuilding.TeamBuildingInputStatus;
import com.blackcompany.eeos.target.persistence.teambuilding.TeamBuildingTargetEntity;
import org.springframework.stereotype.Component;

@Component
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.application.repository;

import com.blackcompany.eeos.target.application.model.AttendStatus;
import com.blackcompany.eeos.target.application.model.AttendWeightPolicyModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.blackcompany.eeos.common.utils.RequestScope;
import com.blackcompany.eeos.member.application.model.ActiveStatus;
import com.blackcompany.eeos.member.application.model.MemberModel;
import com.blackcompany.eeos.member.application.model.converter.MemberEntityConverter;
import com.blackcompany.eeos.member.application.repository.MemberRepository;
import com.blackcompany.eeos.member.application.service.QueryMemberService;
import com.blackcompany.eeos.program.application.exception.NotFoundProgramException;
Expand All @@ -19,6 +18,7 @@
import com.blackcompany.eeos.target.application.dto.AttendInfoWithProgramResponse;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyRankingResponse;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyResponse;
import com.blackcompany.eeos.target.application.dto.AttendStatisticsResponse.MemberStatistics;
import com.blackcompany.eeos.target.application.dto.AttendSummaryInfoResponse;
import com.blackcompany.eeos.target.application.dto.ChangeAttendStatusResponse;
import com.blackcompany.eeos.target.application.dto.QueryAttendActiveStatusResponse;
Expand All @@ -45,8 +45,8 @@
import com.blackcompany.eeos.target.persistence.AttendEntity;
import com.blackcompany.eeos.target.persistence.AttendRepository;
import com.blackcompany.eeos.target.persistence.PenaltyPointRepository;
import com.blackcompany.eeos.target.persistence.ProgramRankCounterEntity;
import com.blackcompany.eeos.target.persistence.ProgramRankCounterRepository;
import com.blackcompany.eeos.target.persistence.rank.ProgramRankCounterEntity;
import com.blackcompany.eeos.target.persistence.rank.ProgramRankCounterRepository;
import java.sql.Timestamp;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -76,7 +76,6 @@ public class AttendService
private final AttendEntityConverter attendEntityConverter;
private final QueryMemberService queryMemberService;
private final ChangeAttendStatusConverter changeAttendStatusConverter;
private final MemberEntityConverter memberEntityConverter;
private final AttendInfoConverter attendInfoConverter;
private final QueryAttendStatusResponseConverter attendStatusResponseConverter;
private final AttendInfoActiveStatusConverter attendInfoActiveStatusConverter;
Expand Down Expand Up @@ -348,6 +347,62 @@ public AttendPenaltyRankingResponse getMyPenaltyRanking(int rankOffset) {
return new AttendPenaltyRankingResponse(myPenaltyRank < rankOffset, (int) myPenaltyRank);
}

@Override
public PageResponse<MemberStatistics> getStatistics(
int page, int size, String activeStatus, Long startDate, Long endDate) {

Sort.Order penaltyScore = Sort.Order.desc("penaltyScore");
Sort.Order absent = Sort.Order.desc("absent");
Sort.Order late = Sort.Order.desc("late");

Pageable pageable = PageRequest.of(page - 1, size, Sort.by(penaltyScore, absent, late));

Timestamp startTimestamp =
startDate == null
? semesterPeriodProvider.getSemesterPeriod().getStartDate()
: new Timestamp(startDate);
Timestamp endTimestamp =
endDate == null
? semesterPeriodProvider.getSemesterPeriod().getEndDate()
: new Timestamp(endDate);

Page<Object[]> pages;

if (activeStatus == null || activeStatus.equalsIgnoreCase("all"))
pages =
attendRepository.getStatistics(
startTimestamp, endTimestamp, AttendStatus.LATE, AttendStatus.ABSENT, pageable);
else
pages =
attendRepository.getStatistics(
startTimestamp,
endTimestamp,
AttendStatus.LATE,
AttendStatus.ABSENT,
ActiveStatus.find(activeStatus),
pageable);

if (pages.getTotalElements() != 0) {
List<MemberStatistics> statistics =
pages
.get()
.map(
obj ->
new MemberStatistics(
(Long) obj[0],
(String) obj[1],
((ActiveStatus) obj[2]).getStatus(),
((Long) obj[3]).intValue(),
((Long) obj[4]).intValue(),
((Long) obj[5]).intValue()))
.toList();

return new PageResponse<>(new PageImpl<>(statistics, pageable, pages.getTotalElements()));
}

return new PageResponse<>(Page.empty(PageRequest.of(page - 1, size)));
}

private List<AttendModel> findMyAttends(List<ProgramModel> programs) {
Long memberId = RequestScope.getMemberId();
return attendRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import com.blackcompany.eeos.target.application.usecase.AttendTeamBuildingUsecase;
import com.blackcompany.eeos.target.application.usecase.GetTargetInfoUsecase;
import com.blackcompany.eeos.target.application.usecase.UpdateAttendTeamBuildingUsecase;
import com.blackcompany.eeos.target.persistence.TeamBuildingTargetEntity;
import com.blackcompany.eeos.target.persistence.TeamBuildingTargetRepository;
import com.blackcompany.eeos.target.persistence.teambuilding.TeamBuildingTargetEntity;
import com.blackcompany.eeos.target.persistence.teambuilding.TeamBuildingTargetRepository;
import com.blackcompany.eeos.teamBuilding.application.model.TeamBuildingModel;
import com.blackcompany.eeos.teamBuilding.application.model.converter.TeamBuildingEntityConverter;
import com.blackcompany.eeos.teamBuilding.application.service.QueryTeamBuildingService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.blackcompany.eeos.target.application.model.AttendStatus;
import com.blackcompany.eeos.target.application.model.AttendWeightPolicyModel;
import com.blackcompany.eeos.target.application.model.SignType;
import com.blackcompany.eeos.target.persistence.AttendWeightPolicyRepository;
import com.blackcompany.eeos.target.application.repository.AttendWeightPolicyRepository;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import com.blackcompany.eeos.target.application.model.AttendStatus;
import com.blackcompany.eeos.target.application.model.AttendWeightPolicyModel;
import com.blackcompany.eeos.target.application.model.SignType;
import com.blackcompany.eeos.target.application.repository.AttendWeightPolicyRepository;
import com.blackcompany.eeos.target.application.usecase.CommandAttendWeightPolicyUsecase;
import com.blackcompany.eeos.target.application.usecase.GetAttendWeightPolicyUsecase;
import com.blackcompany.eeos.target.persistence.AttendWeightPolicyRepository;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.blackcompany.eeos.target.application.exception.NotFoundTargetTeamBuildingException;
import com.blackcompany.eeos.target.application.model.TeamBuildingTargetModel;
import com.blackcompany.eeos.target.application.model.converter.TeamBuildingTargetEntityConverter;
import com.blackcompany.eeos.target.persistence.TeamBuildingTargetRepository;
import com.blackcompany.eeos.target.persistence.teambuilding.TeamBuildingTargetRepository;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.blackcompany.eeos.target.application.service;

import com.blackcompany.eeos.target.application.usecase.PresentTeamUsecase;
import com.blackcompany.eeos.target.persistence.PresentationEntity;
import com.blackcompany.eeos.target.persistence.PresentationRepository;
import com.blackcompany.eeos.target.persistence.converter.PresentationConverter;
import com.blackcompany.eeos.target.persistence.presentation.PresentationEntity;
import com.blackcompany.eeos.target.persistence.presentation.PresentationRepository;
import com.blackcompany.eeos.team.application.exception.NotFoundTeamException;
import com.blackcompany.eeos.team.application.model.converter.TeamEntityConverter;
import com.blackcompany.eeos.team.persistence.TeamRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.blackcompany.eeos.target.application.dto.AttendInfoWithProgramResponse;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyRankingResponse;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyResponse;
import com.blackcompany.eeos.target.application.dto.AttendStatisticsResponse.MemberStatistics;
import com.blackcompany.eeos.target.application.dto.AttendSummaryInfoResponse;
import com.blackcompany.eeos.target.application.dto.QueryAttendStatusResponse;
import java.util.List;
Expand Down Expand Up @@ -32,4 +33,7 @@ PageResponse<AttendPenaltyResponse> getPenaltyInfos(
AttendSummaryInfoResponse getMyAttendSummary(Long startDate, Long endDate);

AttendPenaltyRankingResponse getMyPenaltyRanking(int rankOffset);

PageResponse<MemberStatistics> getStatistics(
int page, int size, String activeStatus, Long startDate, Long endDate);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.blackcompany.eeos.target.persistence;

import com.blackcompany.eeos.member.application.model.ActiveStatus;
import com.blackcompany.eeos.target.application.model.AttendStatus;
import jakarta.persistence.LockModeType;
import java.sql.Timestamp;
Expand Down Expand Up @@ -65,4 +66,39 @@ Page<AttendEntity> findAllByMemberIdAndCreatedDateGreaterThan(
@Param("startDate") Timestamp startDate,
@Param("endDate") Timestamp endDate,
Pageable pageable);

@Query(
"SELECT"
+ " m.id,"
+ " m.name,"
+ " m.activeStatus,"
+ " SUM(CASE WHEN a.status = :late THEN 1 ELSE 0 END) as late,"
+ " SUM (CASE WHEN a.status = :absent THEN 1 ELSE 0 END ) as absent,"
+ " COALESCE(SUM (a.penaltyScore), 0) as penaltyScore "
+ "FROM AttendEntity a JOIN MemberEntity m ON a.memberId=m.id WHERE a.createdDate >= :startDate AND a.createdDate <= :endDate "
+ "GROUP BY m.id, m.name")
Page<Object[]> getStatistics(
@Param("startDate") Timestamp startDate,
@Param("endDate") Timestamp endDate,
@Param("late") AttendStatus late,
@Param("absent") AttendStatus absent,
Pageable pageable);

@Query(
"SELECT"
+ " m.id,"
+ " m.name,"
+ " m.activeStatus,"
+ " SUM(CASE WHEN a.status = :late THEN 1 ELSE 0 END) as late,"
+ " SUM (CASE WHEN a.status = :absent THEN 1 ELSE 0 END ) as absent,"
+ " COALESCE(SUM (a.penaltyScore), 0) as penaltyScore "
+ "FROM AttendEntity a JOIN MemberEntity m ON a.memberId=m.id WHERE a.isDeleted=false AND a.createdDate >= :startDate AND a.createdDate <= :endDate AND m.activeStatus=:activeStatus "
+ "GROUP BY m.id, m.name, m.activeStatus")
Page<Object[]> getStatistics(
@Param("startDate") Timestamp startDate,
@Param("endDate") Timestamp endDate,
@Param("late") AttendStatus late,
@Param("absent") AttendStatus absent,
@Param("activeStatus") ActiveStatus activeStatus,
Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.blackcompany.eeos.target.persistence.converter;

import com.blackcompany.eeos.target.persistence.PresentationEntity;
import com.blackcompany.eeos.target.persistence.presentation.PresentationEntity;
import org.springframework.stereotype.Component;

@Component
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.policy;

import com.blackcompany.eeos.common.persistence.BaseEntity;
import com.blackcompany.eeos.target.application.model.AttendStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.policy;

import com.blackcompany.eeos.target.application.model.AttendStatus;
import com.blackcompany.eeos.target.application.model.AttendWeightPolicyModel;
import com.blackcompany.eeos.target.application.repository.AttendWeightPolicyRepository;
import java.util.Collection;
import java.util.List;
import java.util.Set;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.policy;

import com.blackcompany.eeos.target.application.model.AttendStatus;
import java.util.Collection;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.presentation;

import com.blackcompany.eeos.common.persistence.BaseEntity;
import jakarta.persistence.Column;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.presentation;

import com.blackcompany.eeos.team.persistence.TeamEntity;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.rank;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.rank;

import jakarta.persistence.LockModeType;
import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.teambuilding;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.teambuilding;

import com.blackcompany.eeos.target.application.exception.NotFoundTeamBuildingInputStatus;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.teambuilding;

import com.blackcompany.eeos.common.persistence.BaseEntity;
import jakarta.persistence.Column;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.blackcompany.eeos.target.persistence;
package com.blackcompany.eeos.target.persistence.teambuilding;

import java.util.List;
import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.blackcompany.eeos.target.application.dto.AttendInfosSearchRequest;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyRankingResponse;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyResponse;
import com.blackcompany.eeos.target.application.dto.AttendStatisticsResponse.MemberStatistics;
import com.blackcompany.eeos.target.application.dto.AttendSummaryInfoResponse;
import com.blackcompany.eeos.target.application.dto.ChangeAttendStatusResponse;
import com.blackcompany.eeos.target.application.dto.PenaltyInfoRequest;
Expand Down Expand Up @@ -139,4 +140,18 @@ public ApiResponse<SuccessBody<AttendPenaltyRankingResponse>> getMyPenaltyRankin
AttendPenaltyRankingResponse response = getAttendantInfoUsecase.getMyPenaltyRanking(rankOffset);
return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.GET);
}

@Override
@GetMapping("/attend/statistic")
public ApiResponse<SuccessBody<PageResponse<MemberStatistics>>> getStatistics(
@RequestParam("size") int size,
@RequestParam("page") int page,
@RequestParam("activeStatus") String activeStatus,
@RequestParam(value = "startDate", required = false) Long startDate,
@RequestParam(value = "endDate", required = false) Long endDate) {
PageResponse<MemberStatistics> response =
getAttendantInfoUsecase.getStatistics(page, size, activeStatus, startDate, endDate);

return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.CREATE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.blackcompany.eeos.target.application.dto.AttendInfosSearchRequest;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyRankingResponse;
import com.blackcompany.eeos.target.application.dto.AttendPenaltyResponse;
import com.blackcompany.eeos.target.application.dto.AttendStatisticsResponse.MemberStatistics;
import com.blackcompany.eeos.target.application.dto.AttendSummaryInfoResponse;
import com.blackcompany.eeos.target.application.dto.ChangeAttendStatusResponse;
import com.blackcompany.eeos.target.application.dto.PenaltyInfoRequest;
Expand Down Expand Up @@ -73,4 +74,8 @@ ApiResponse<SuccessBody<AttendSummaryInfoResponse>> getMyAttendSummaryInfo(

@Operation(summary = "나의 벌점 순위 조회", description = "나의 벌점 순위를 조회합니다.")
ApiResponse<SuccessBody<AttendPenaltyRankingResponse>> getMyPenaltyRankingInfo(int rankOffset);

@Operation(summary = "전체 출석 통계 조회", description = "전체 회원의 출석 통계를 조회합니다.")
ApiResponse<SuccessBody<PageResponse<MemberStatistics>>> getStatistics(
int size, int page, String memberStatus, Long startDate, Long endDate);
}
Loading