Skip to content

Commit

Permalink
[Feature/issue-24] 출석체크 현황 조회 수정
Browse files Browse the repository at this point in the history
[Feature/issue-24]  출석체크 현황 조회 수정
  • Loading branch information
dlgocks1 authored Nov 25, 2023
2 parents d231e92 + 5f94b0e commit c26e5e7
Show file tree
Hide file tree
Showing 21 changed files with 137 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import com.example.cmc_be.attendance.dto.AttendanceReq
import com.example.cmc_be.attendance.dto.AttendanceRes
import com.example.cmc_be.attendance.service.AttendanceService
import com.example.cmc_be.attendance.service.QrCodeService
import com.example.cmc_be.common.exeption.BadRequestException
import com.example.cmc_be.common.response.CommonResponse
import com.example.cmc_be.domain.attendance.exception.AttendanceErrorCode
import com.example.cmc_be.domain.generation.repository.GenerationWeeksInfoRepository
import com.example.cmc_be.domain.user.entity.User
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
Expand All @@ -17,15 +20,25 @@ import org.springframework.web.bind.annotation.*
@Tag(name = "ADMIN-03 Attendance 출석 관련 API")
class AdminAttendanceController(
private val qrCodeService: QrCodeService,
private val attendanceService: AttendanceService
private val attendanceService: AttendanceService,
private val generationWeeksInfoRepository: GenerationWeeksInfoRepository
) {
@PostMapping("/code")
@Operation(summary = "03-01 출석용 코드 생성(중복 생성 가능)")
fun generateCode(
@AuthenticationPrincipal user: User,
@RequestBody gernerateCode: AttendanceReq.GenerateCode
): CommonResponse<String> {
return CommonResponse.onSuccess(qrCodeService.generateCode(gernerateCode))
val generationWeeksInfo = generationWeeksInfoRepository.findFirstByGenerationAndWeek(
generation = gernerateCode.generation, week = gernerateCode.week
) ?: throw BadRequestException(AttendanceErrorCode.CANNOT_ACCESS_ATEENDANCE)

return CommonResponse.onSuccess(
qrCodeService.generateCode(
generationReq = gernerateCode,
generationWeeksInfo = generationWeeksInfo
)
)
}

@GetMapping("/code")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AttendanceController(
) {
@GetMapping("")
@Operation(summary = "03-01 출석 현황 조회")
fun getAttendanceList(@AuthenticationPrincipal user: User): CommonResponse<List<AttendanceRes.AttendanceInfoDto>> {
fun getAttendanceList(@AuthenticationPrincipal user: User): CommonResponse<AttendanceRes.GetAttendances> {
return CommonResponse.onSuccess(attendanceService.getAttendanceList(user))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,47 @@ import com.example.cmc_be.attendance.dto.AttendanceRes
import com.example.cmc_be.common.annotation.Convertor
import com.example.cmc_be.domain.attendance.entity.Attendance
import com.example.cmc_be.domain.attendance.entity.AttendanceCode
import com.example.cmc_be.domain.attendance.enums.AttendanceCategory
import com.example.cmc_be.domain.attendance.enums.AttendanceHour
import com.example.cmc_be.domain.attendance.enums.AttendanceStatus
import com.example.cmc_be.domain.generation.entity.GenerationWeeksInfo
import com.example.cmc_be.domain.user.entity.User
import java.time.ZoneId
import java.time.ZonedDateTime

@Convertor
class AttendanceConverter {

fun getAttendanceList(
allGenerationWeeksInfo: List<GenerationWeeksInfo>,
userAllAttendanceData: Map<Int, List<Attendance>>
) = allGenerationWeeksInfo.map {
val week = it.week
val firstHour =
(userAllAttendanceData[week]?.find { it.attendanceHour == AttendanceHour.FIRST_HOUR })?.attendanceStatus
?: AttendanceStatus.ABSENT
val secondHour =
(userAllAttendanceData[week]?.find { it.attendanceHour == AttendanceHour.SECOND_HOUR })?.attendanceStatus
?: AttendanceStatus.ABSENT
AttendanceRes.AttendanceInfoDto(
week = week,
firstHour = firstHour,
secondHour = secondHour,
): AttendanceRes.GetAttendances {
val attendances = allGenerationWeeksInfo.map { generationWeekInfo ->
val week = generationWeekInfo.week
val firstHour =
(userAllAttendanceData[week]?.find { it.attendanceHour == AttendanceHour.FIRST_HOUR })?.attendanceCategory
?: AttendanceCategory.ABSENT
val secondHour =
(userAllAttendanceData[week]?.find { it.attendanceHour == AttendanceHour.SECOND_HOUR })?.attendanceCategory
?: AttendanceCategory.ABSENT
val currentDateTime = ZonedDateTime.now(ZoneId.systemDefault())
val currentDate = currentDateTime.toLocalDate()

AttendanceRes.AttendanceInfoDto(
week = week,
firstHour = firstHour,
secondHour = secondHour,
isOffline = generationWeekInfo.isOffline,
enable = currentDate.isAfter(generationWeekInfo.date.minusDays(1L))
)
}
val enableAttendances = attendances.filter { it.enable }
return AttendanceRes.GetAttendances(
attendanceStatus = AttendanceRes.AttendanceStatus(
attendanceCount = enableAttendances.count { it.firstHour == AttendanceCategory.ATTENDANCE } + enableAttendances.count { it.secondHour == AttendanceCategory.ATTENDANCE },
lateCount = enableAttendances.count { it.firstHour == AttendanceCategory.LATE } + enableAttendances.count { it.secondHour == AttendanceCategory.LATE },
absentCount = enableAttendances.count { it.firstHour == AttendanceCategory.ABSENT } + enableAttendances.count { it.secondHour == AttendanceCategory.ABSENT },
),
attandances = attendances
)
}

Expand All @@ -36,31 +54,39 @@ class AttendanceConverter {
allGeneration: List<GenerationWeeksInfo>
) = allUsers.map { user ->
val userAttandances = allAttendances.filter { it.user.id == user.id }
val attendances = allGeneration.map { generationInfo ->
val userAllAttendanceData =
userAttandances.filter { it.generationWeeksInfo.week == generationInfo.week }
val firstHour =
(userAllAttendanceData.find { it.attendanceHour == AttendanceHour.FIRST_HOUR })?.attendanceCategory
?: AttendanceCategory.ABSENT
val secondHour =
(userAllAttendanceData.find { it.attendanceHour == AttendanceHour.SECOND_HOUR })?.attendanceCategory
?: AttendanceCategory.ABSENT
AttendanceRes.AttendanceInfoDto(
week = generationInfo.week,
firstHour = firstHour,
secondHour = secondHour,
isOffline = generationInfo.isOffline,
enable = true
)
}
AttendanceRes.AllAttendanceInfoDto(
name = user.name,
role = user.role,
nickname = user.nickname,
attandances = allGeneration.map { generationInfo ->
val userAllAttendanceData =
userAttandances.filter { it.generationWeeksInfo.week == generationInfo.week }
val firstHour =
(userAllAttendanceData.find { it.attendanceHour == AttendanceHour.FIRST_HOUR })?.attendanceStatus
?: AttendanceStatus.ABSENT
val secondHour =
(userAllAttendanceData.find { it.attendanceHour == AttendanceHour.SECOND_HOUR })?.attendanceStatus
?: AttendanceStatus.ABSENT
AttendanceRes.AttendanceInfoDto(
week = generationInfo.week,
firstHour = firstHour,
secondHour = secondHour
)
}
attendanceStatus = AttendanceRes.AttendanceStatus(
attendanceCount = attendances.count { it.firstHour == AttendanceCategory.ATTENDANCE } + attendances.count { it.secondHour == AttendanceCategory.ATTENDANCE },
lateCount = attendances.count { it.firstHour == AttendanceCategory.LATE } + attendances.count { it.secondHour == AttendanceCategory.LATE },
absentCount = attendances.count { it.firstHour == AttendanceCategory.ABSENT } + attendances.count { it.secondHour == AttendanceCategory.ABSENT },
),
attandances = attendances
)
}

fun getCodeInfo(codeInfo: AttendanceCode): AttendanceRes.AttendanceCodeDto {
return AttendanceRes.AttendanceCodeDto(
availableDate = codeInfo.availableDate,
availableDate = codeInfo.generationWeeksInfo.date,
startTime = codeInfo.startTime,
endTime = codeInfo.endTime,
lateMinute = codeInfo.lateMinute
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.example.cmc_be.attendance.dto

import io.swagger.v3.oas.annotations.media.Schema
import java.time.LocalDate
import java.time.LocalTime

class AttendanceReq {
Expand All @@ -17,7 +16,6 @@ class AttendanceReq {
val week: Int,
@Schema(example = "1")
val hour: Int,
val availableDate: LocalDate,
val startTime: HourAndMinute,
val endTime: HourAndMinute,
@Schema(example = "15")
Expand Down
21 changes: 17 additions & 4 deletions src/main/kotlin/com/example/cmc_be/attendance/dto/AttendanceRes.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.example.cmc_be.attendance.dto

import com.example.cmc_be.domain.attendance.enums.AttendanceStatus
import com.example.cmc_be.domain.user.enums.UserRole
import com.example.cmc_be.domain.attendance.enums.AttendanceCategory
import java.time.LocalDate
import java.time.LocalTime

class AttendanceRes {
data class AttendanceInfoDto(
val week: Int,
val firstHour: AttendanceStatus,
val secondHour: AttendanceStatus
val firstHour: AttendanceCategory,
val secondHour: AttendanceCategory,
val isOffline: Boolean,
val enable: Boolean,
)

data class AttendanceCodeDto(
Expand All @@ -23,6 +24,18 @@ class AttendanceRes {
val name: String,
val role: String,
val nickname: String,
val attendanceStatus: AttendanceStatus,
val attandances: List<AttendanceInfoDto>
)

data class GetAttendances(
val attendanceStatus: AttendanceStatus,
val attandances: List<AttendanceInfoDto>
)

data class AttendanceStatus(
val attendanceCount: Int,
val lateCount: Int,
val absentCount: Int
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import com.example.cmc_be.attendance.dto.AttendanceReq
import com.example.cmc_be.attendance.dto.AttendanceRes
import com.example.cmc_be.common.exeption.NotFoundException
import com.example.cmc_be.domain.attendance.entity.Attendance
import com.example.cmc_be.domain.attendance.enums.AttendanceStatus
import com.example.cmc_be.domain.attendance.enums.AttendanceCategory
import com.example.cmc_be.domain.attendance.repository.AttendanceRepository
import com.example.cmc_be.domain.generation.repository.GenerationWeeksInfoRepository
import com.example.cmc_be.domain.notification.exception.NotificationExceptionErrorCode
Expand All @@ -21,18 +21,22 @@ class AttendanceService(
private val attendanceConverter: AttendanceConverter,
private val qrCodeService: QrCodeService
) {
fun getAttendanceList(user: User): List<AttendanceRes.AttendanceInfoDto> {
fun getAttendanceList(user: User): AttendanceRes.GetAttendances {
val allGenerationWeeksInfo =
generationWeeksInfoRepository.findAllByGeneration(user.nowGeneration).sortedBy { it.week }
val userAllAttendanceData =
attendanceRepository.findAllByUserId(user.id).groupBy { it.generationWeeksInfo.week }
return attendanceConverter.getAttendanceList(allGenerationWeeksInfo, userAllAttendanceData)

return attendanceConverter.getAttendanceList(
allGenerationWeeksInfo = allGenerationWeeksInfo,
userAllAttendanceData = userAllAttendanceData
)
}

fun setAttendance(user: User, code: AttendanceReq.AttendanceCode): String {
val attendanceCode = qrCodeService.getCode(code.code)
qrCodeService.validateCode(user, attendanceCode)
val attendanceStatus = if (attendanceCode.isLate()) AttendanceStatus.LATE else AttendanceStatus.ATTENDANCE
val attendanceCategory = if (attendanceCode.isLate()) AttendanceCategory.LATE else AttendanceCategory.ATTENDANCE

attendanceRepository.save(
Attendance(
Expand All @@ -41,11 +45,11 @@ class AttendanceService(
user.nowGeneration,
attendanceCode.week
) ?: throw NotFoundException(NotificationExceptionErrorCode.NOT_FOUND_LATEST_NOTIFICATION),
attendanceStatus = attendanceStatus,
attendanceCategory = attendanceCategory,
attendanceHour = attendanceCode.hour
)
)
return "${attendanceStatus.status}하였습니다."
return "${attendanceCategory.status}하였습니다."
}

fun getParticipantsAttendance(generation: Int): List<AttendanceRes.AllAttendanceInfoDto> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.example.cmc_be.domain.attendance.entity.AttendanceCode
import com.example.cmc_be.domain.attendance.enums.AttendanceHour
import com.example.cmc_be.domain.attendance.exception.AttendanceErrorCode
import com.example.cmc_be.domain.attendance.repository.AttendanceCodeRepository
import com.example.cmc_be.domain.generation.entity.GenerationWeeksInfo
import com.example.cmc_be.domain.user.entity.User
import org.springframework.data.repository.findByIdOrNull
import org.springframework.scheduling.annotation.Scheduled
Expand All @@ -22,7 +23,10 @@ class QrCodeService(
private val attendanceCodeConverter: AttendanceConverter
) {

fun generateCode(generationReq: AttendanceReq.GenerateCode): String {
fun generateCode(
generationReq: AttendanceReq.GenerateCode,
generationWeeksInfo: GenerationWeeksInfo
): String {
return generateUniqueRandomCode().also { randomCode ->
attendanceCodeRepository.save(
AttendanceCode(
Expand All @@ -31,8 +35,8 @@ class QrCodeService(
week = generationReq.week,
hour = AttendanceHour.of(generationReq.hour),
startTime = generationReq.startTime.toLocalTime(),
availableDate = generationReq.availableDate,
endTime = generationReq.endTime.toLocalTime(),
generationWeeksInfo = generationWeeksInfo,
lateMinute = generationReq.lateMinute
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.example.cmc_be.domain.attendance.entity

import com.example.cmc_be.common.dto.BaseEntity
import com.example.cmc_be.domain.attendance.enums.AttendanceCategory
import com.example.cmc_be.domain.attendance.enums.AttendanceHour
import com.example.cmc_be.domain.attendance.enums.AttendanceStatus
import com.example.cmc_be.domain.generation.entity.GenerationWeeksInfo
import com.example.cmc_be.domain.user.entity.User
import jakarta.persistence.*
Expand All @@ -23,10 +23,10 @@ class Attendance(
@JoinColumn(name = "userId", nullable = false, updatable = false)
val user: User,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "weekId", nullable = false, updatable = false)
@JoinColumn(name = "generationWeeksInfoId", nullable = false, updatable = false)
val generationWeeksInfo: GenerationWeeksInfo,
@Enumerated(EnumType.STRING)
val attendanceStatus: AttendanceStatus,
val attendanceCategory: AttendanceCategory,
@Enumerated(EnumType.STRING)
val attendanceHour: AttendanceHour
) : BaseEntity() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package com.example.cmc_be.domain.attendance.entity
import com.example.cmc_be.common.exeption.BadRequestException
import com.example.cmc_be.domain.attendance.enums.AttendanceHour
import com.example.cmc_be.domain.attendance.exception.AttendanceErrorCode
import com.example.cmc_be.domain.generation.entity.GenerationWeeksInfo
import jakarta.persistence.*
import org.hibernate.annotations.BatchSize
import org.hibernate.annotations.DynamicInsert
import org.hibernate.annotations.DynamicUpdate
import java.time.LocalDate
import java.time.LocalTime
import java.time.ZoneId
import java.time.ZonedDateTime
Expand All @@ -24,7 +24,9 @@ data class AttendanceCode(
val generation: Int,
val week: Int,
@Enumerated(EnumType.STRING) val hour: AttendanceHour,
val availableDate: LocalDate,
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "generationWeeksInfoId", nullable = false, updatable = false)
val generationWeeksInfo: GenerationWeeksInfo,
val startTime: LocalTime,
val endTime: LocalTime,
val lateMinute: Long,
Expand All @@ -34,7 +36,7 @@ data class AttendanceCode(
val currentDate = currentDateTime.toLocalDate()
val currentTime = currentDateTime.toLocalTime()

if (!currentDate.isEqual(availableDate)) {
if (!currentDate.isEqual(generationWeeksInfo.date)) {
return BadRequestException(AttendanceErrorCode.INVALID_CODE)
}
if (currentTime.isBefore(startTime) || currentTime.isAfter(endTime.plusMinutes(lateMinute))) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.example.cmc_be.domain.attendance.enums

enum class AttendanceStatus(
enum class AttendanceCategory(
val value: String,
val status: String
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class GenerationWeeksInfo(
val id: Long = 0L,
val generation: Int,
val week: Int,
val weekStart: LocalDate,
val weekEnd: LocalDate,
val attendanceDate: LocalDate
val date: LocalDate,
val isOffline: Boolean
) : BaseEntity()
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ interface GenerationWeeksInfoRepository : JpaRepository<GenerationWeeksInfo, Lon
fun findAllByGeneration(generation: Int): List<GenerationWeeksInfo>

fun findByGenerationAndWeek(generation: Int, week: Int): GenerationWeeksInfo?

fun findFirstByGenerationAndWeek(generation: Int, week: Int): GenerationWeeksInfo?
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ class GenerationConvertor {
return GenerationWeeksInfo(
generation = generationInfo.generation,
week = generationInfo.week,
weekStart = generationInfo.weekStart,
weekEnd = generationInfo.weekEnd,
attendanceDate = generationInfo.attendanceDate
date = generationInfo.date,
isOffline = generationInfo.isOffline
)
}
}
Loading

0 comments on commit c26e5e7

Please sign in to comment.