Skip to content

Commit

Permalink
merge: (#556) 외출 신청내역 엑셀 출력 api
Browse files Browse the repository at this point in the history
  • Loading branch information
alsdl0629 authored Feb 19, 2024
2 parents 381f566 + de7f457 commit d585fa4
Show file tree
Hide file tree
Showing 17 changed files with 250 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package team.aliens.dms.domain.file.service

import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import team.aliens.dms.domain.point.model.PointHistory
import team.aliens.dms.domain.remain.dto.StudentRemainInfo
import team.aliens.dms.domain.student.model.Student
Expand All @@ -25,4 +26,6 @@ interface WriteFileService {
timeSlots: List<TimeSlot>,
studentSeats: List<StudentSeatInfo>
): ByteArray

fun writeOutingApplicationExcelFile(outingApplicationVos: List<OutingApplicationVO>): ByteArray
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package team.aliens.dms.domain.file.service

import org.springframework.stereotype.Service
import team.aliens.dms.domain.file.spi.WriteFilePort
import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import team.aliens.dms.domain.point.model.PointHistory
import team.aliens.dms.domain.remain.dto.StudentRemainInfo
import team.aliens.dms.domain.student.model.Student
Expand Down Expand Up @@ -33,4 +34,7 @@ class WriteFileServiceImpl(
timeSlots: List<TimeSlot>,
studentSeats: List<StudentSeatInfo>
) = writeFilePort.writeStudyRoomApplicationStatusExcelFile(timeSlots, studentSeats)

override fun writeOutingApplicationExcelFile(outingApplicationVos: List<OutingApplicationVO>) =
writeFilePort.writeOutingApplicationExcelFile(outingApplicationVos)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package team.aliens.dms.domain.file.spi

import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import team.aliens.dms.domain.point.model.PointHistory
import team.aliens.dms.domain.remain.dto.StudentRemainInfo
import team.aliens.dms.domain.student.model.Student
Expand All @@ -25,4 +26,6 @@ interface WriteFilePort {
timeSlots: List<TimeSlot>,
studentSeats: List<StudentSeatInfo>
): ByteArray

fun writeOutingApplicationExcelFile(outingApplicationVos: List<OutingApplicationVO>): ByteArray
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ package team.aliens.dms.domain.outing.dto
data class GetAllOutingTypeTitlesResponse(
val titles: List<String>
)

data class ExportAllOutingApplicationsResponse(
val file: ByteArray,
val fileName: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class CommandOutingServiceImpl(

override fun saveOutingApplication(outingApplication: OutingApplication): OutingApplication {
val savedOutingApplication = commandOutingApplicationPort.saveOutingApplication(outingApplication)
.copy(companionIds = outingApplication.companionIds)

saveAllOutingCompanions(savedOutingApplication)

return savedOutingApplication
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package team.aliens.dms.domain.outing.service

import team.aliens.dms.domain.outing.model.OutingType
import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import java.time.LocalDate
import java.util.UUID

interface GetOutingService {

fun getOutingType(outingType: OutingType): OutingType

fun getAllOutingTypeTitlesBySchoolIdAndKeyword(schoolId: UUID, keyword: String?): List<String>

fun getAllOutingApplicationVOsBetweenStartAndEnd(start: LocalDate, end: LocalDate): List<OutingApplicationVO>
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@ package team.aliens.dms.domain.outing.service
import org.springframework.stereotype.Service
import team.aliens.dms.domain.outing.exception.OutingTypeNotFoundException
import team.aliens.dms.domain.outing.model.OutingType
import team.aliens.dms.domain.outing.spi.QueryOutingApplicationPort
import team.aliens.dms.domain.outing.spi.QueryOutingTypePort
import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import java.time.LocalDate
import java.util.UUID

@Service
class GetOutingServiceImpl(
private val queryOutingTypePort: QueryOutingTypePort
private val queryOutingTypePort: QueryOutingTypePort,
private val queryOutingApplicationPort: QueryOutingApplicationPort
) : GetOutingService {

override fun getOutingType(outingType: OutingType): OutingType =
override fun getOutingType(outingType: OutingType) =
queryOutingTypePort.queryOutingType(outingType) ?: throw OutingTypeNotFoundException

override fun getAllOutingTypeTitlesBySchoolIdAndKeyword(schoolId: UUID, keyword: String?): List<String> =
override fun getAllOutingTypeTitlesBySchoolIdAndKeyword(schoolId: UUID, keyword: String?) =
queryOutingTypePort.queryAllOutingTypeTitlesBySchoolIdAndKeyword(schoolId, keyword)

override fun getAllOutingApplicationVOsBetweenStartAndEnd(start: LocalDate, end: LocalDate) =
queryOutingApplicationPort.queryAllOutingApplicationVOsBetweenStartAndEnd(start, end)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package team.aliens.dms.domain.outing.spi

import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import java.time.LocalDate
import java.util.UUID

interface QueryOutingApplicationPort {

fun existOutingApplicationByOutAtAndStudentId(outAt: LocalDate, studentId: UUID): Boolean

fun queryAllOutingApplicationVOsBetweenStartAndEnd(start: LocalDate, end: LocalDate): List<OutingApplicationVO>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package team.aliens.dms.domain.outing.spi.vo

import team.aliens.dms.domain.student.model.Student
import java.time.LocalDate
import java.time.LocalTime

open class OutingApplicationVO(
val studentName: String,
val studentGrade: Int,
val studentClassRoom: Int,
val studentNumber: Int,
val outAt: LocalDate,
val outingTime: LocalTime,
val arrivalTime: LocalTime,
val outingCompanionVOs: List<OutingCompanionVO>
) {
val studentGcn = Student.processGcn(studentGrade, studentClassRoom, studentNumber)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package team.aliens.dms.domain.outing.spi.vo

import team.aliens.dms.domain.student.model.Student

open class OutingCompanionVO(
val studentName: String,
val studentGrade: Int,
val studentClassRoom: Int,
val studentNumber: Int
) {
val studentGcn: String
get() =
if (studentGrade != 0 && studentClassRoom != 0 && studentNumber != 0)
Student.processGcn(studentGrade, studentClassRoom, studentNumber)
else ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package team.aliens.dms.domain.outing.usecase

import team.aliens.dms.common.annotation.ReadOnlyUseCase
import team.aliens.dms.domain.file.model.File
import team.aliens.dms.domain.file.service.FileService
import team.aliens.dms.domain.outing.dto.ExportAllOutingApplicationsResponse
import team.aliens.dms.domain.outing.service.OutingService
import team.aliens.dms.domain.school.service.SchoolService
import team.aliens.dms.domain.user.service.UserService
import java.time.LocalDate
import java.time.LocalDateTime

@ReadOnlyUseCase
class ExportAllOutingApplicationsUseCase(
private val outingService: OutingService,
private val fileService: FileService,
private val userService: UserService,
private val schoolService: SchoolService
) {

fun execute(start: LocalDate, end: LocalDate): ExportAllOutingApplicationsResponse {
val outingApplicationVOs = outingService.getAllOutingApplicationVOsBetweenStartAndEnd(start, end)

val file = fileService.writeOutingApplicationExcelFile(outingApplicationVOs)

val user = userService.getCurrentUser()
val school = schoolService.getSchoolById(user.schoolId)

return ExportAllOutingApplicationsResponse(
file = file,
fileName = getFileName(school.name)
)
}

private fun getFileName(schoolName: String) =
"${schoolName.replace(" ", "")}_외출_신청상태_${LocalDateTime.now().format(File.FILE_DATE_FORMAT)}"
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class SecurityConfig(
.requestMatchers(HttpMethod.POST, "/outings/types").hasAuthority(MANAGER.name)
.requestMatchers(HttpMethod.DELETE, "/outings/types/{title}").hasAuthority(MANAGER.name)
.requestMatchers(HttpMethod.GET, "/outings/types").hasAnyAuthority(STUDENT.name, MANAGER.name)
.requestMatchers(HttpMethod.GET, "/outings/files").hasAuthority(MANAGER.name)

.anyRequest().denyAll()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import team.aliens.dms.domain.file.FileExtension.XLSX
import team.aliens.dms.domain.file.spi.ParseFilePort
import team.aliens.dms.domain.file.spi.WriteFilePort
import team.aliens.dms.domain.file.spi.vo.ExcelStudentVO
import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import team.aliens.dms.domain.point.model.PointHistory
import team.aliens.dms.domain.remain.dto.StudentRemainInfo
import team.aliens.dms.domain.student.model.Sex
Expand Down Expand Up @@ -230,7 +231,7 @@ class ExcelAdapter : ParseFilePort, WriteFilePort {
.map {
autoSizeColumn(it)
val width = getColumnWidth(it)
setColumnWidth(it, width + 500)
setColumnWidth(it, width + 900)
}
}
}
Expand Down Expand Up @@ -259,6 +260,33 @@ class ExcelAdapter : ParseFilePort, WriteFilePort {
)
}

override fun writeOutingApplicationExcelFile(outingApplicationVos: List<OutingApplicationVO>): ByteArray {
val attributes = mutableListOf("이름", "학번", "외출일", "외출 시간", "도착 시간")

val maxOutingCompanionCount = outingApplicationVos.maxOf { it.outingCompanionVOs.size }

for (i in 0 until maxOutingCompanionCount) {
val order = i + 1 // ex) 동행1 이름, 동행1 학번
attributes.addAll(listOf("동행${order} 이름", "동행${order} 학번"))
}

val outingApplicationInfosList = outingApplicationVos.map { outingApplication ->
mutableListOf(
outingApplication.studentName,
outingApplication.studentGcn,
outingApplication.outAt.toString(),
outingApplication.outingTime.toString(),
outingApplication.arrivalTime.toString()
).apply {
outingApplication.outingCompanionVOs.forEach { outingCompanion ->
addAll(listOf(outingCompanion.studentName, outingCompanion.studentGcn))
}
}
}

return createExcelSheet(attributes, outingApplicationInfosList)
}

private fun createExcelSheet(
attributes: List<String>,
datasList: List<List<String?>>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,73 @@
package team.aliens.dms.persistence.outing

import com.querydsl.core.group.GroupBy
import com.querydsl.core.group.GroupBy.groupBy
import com.querydsl.core.group.GroupBy.list
import com.querydsl.jpa.impl.JPAQueryFactory
import org.springframework.stereotype.Component
import team.aliens.dms.domain.outing.model.OutingApplication
import team.aliens.dms.domain.outing.spi.OutingApplicationPort
import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import team.aliens.dms.persistence.outing.entity.QOutingApplicationJpaEntity.outingApplicationJpaEntity
import team.aliens.dms.persistence.outing.entity.QOutingCompanionJpaEntity.outingCompanionJpaEntity
import team.aliens.dms.persistence.outing.mapper.OutingApplicationMapper
import team.aliens.dms.persistence.outing.repository.OutingApplicationJpaRepository
import team.aliens.dms.persistence.outing.repository.vo.QQueryOutingApplicationVO
import team.aliens.dms.persistence.outing.repository.vo.QQueryOutingCompanionVO
import team.aliens.dms.persistence.student.entity.QStudentJpaEntity
import team.aliens.dms.persistence.student.entity.QStudentJpaEntity.studentJpaEntity
import java.time.LocalDate
import java.util.UUID

@Component
class OutingApplicationPersistenceAdapter(
private val outingApplicationMapper: OutingApplicationMapper,
private val outingApplicationRepository: OutingApplicationJpaRepository
private val outingApplicationRepository: OutingApplicationJpaRepository,
private val queryFactory: JPAQueryFactory
) : OutingApplicationPort {

override fun existOutingApplicationByOutAtAndStudentId(outAt: LocalDate, studentId: UUID) =
outingApplicationRepository.existsByOutAtAndStudentId(outAt, studentId)

override fun queryAllOutingApplicationVOsBetweenStartAndEnd(
start: LocalDate,
end: LocalDate,
): List<OutingApplicationVO> {
val studentJpaEntity = QStudentJpaEntity("studentJpaEntity")
val outingCompanionStudentJpaEntity = QStudentJpaEntity("outingCompanionStudentJpaEntity")

return queryFactory
.selectFrom(outingApplicationJpaEntity)
.join(outingApplicationJpaEntity.student, studentJpaEntity)
.leftJoin(outingCompanionJpaEntity)
.on(outingApplicationJpaEntity.id.eq(outingCompanionJpaEntity.outingApplication.id))
.leftJoin(outingCompanionJpaEntity.student, outingCompanionStudentJpaEntity)
.where(outingApplicationJpaEntity.outAt.between(start, end))
.orderBy(outingApplicationJpaEntity.outAt.asc())
.transform(
groupBy(outingApplicationJpaEntity.id)
.list(
QQueryOutingApplicationVO(
studentJpaEntity.name,
studentJpaEntity.grade,
studentJpaEntity.classRoom,
studentJpaEntity.number,
outingApplicationJpaEntity.outAt,
outingApplicationJpaEntity.outingTime,
outingApplicationJpaEntity.arrivalTime,
list(
QQueryOutingCompanionVO(
outingCompanionStudentJpaEntity.name,
outingCompanionStudentJpaEntity.grade,
outingCompanionStudentJpaEntity.classRoom,
outingCompanionStudentJpaEntity.number
)
)
)
)
)
}

override fun saveOutingApplication(outingApplication: OutingApplication) =
outingApplicationMapper.toDomain(
outingApplicationRepository.save(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package team.aliens.dms.persistence.outing.repository.vo

import com.querydsl.core.annotations.QueryProjection
import team.aliens.dms.domain.outing.spi.vo.OutingApplicationVO
import team.aliens.dms.domain.outing.spi.vo.OutingCompanionVO
import java.time.LocalDate
import java.time.LocalTime

class QueryOutingApplicationVO @QueryProjection constructor(
studentName: String,
studentGrade: Int,
studentClassRoom: Int,
studentNumber: Int,
outAt: LocalDate,
outingTime: LocalTime,
arrivalTime: LocalTime,
outingCompanionVOs: List<OutingCompanionVO>
) : OutingApplicationVO(
studentName = studentName,
studentGrade = studentGrade,
studentClassRoom = studentClassRoom,
studentNumber = studentNumber,
outAt = outAt,
outingTime = outingTime,
arrivalTime = arrivalTime,
outingCompanionVOs = outingCompanionVOs
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package team.aliens.dms.persistence.outing.repository.vo

import com.querydsl.core.annotations.QueryProjection
import team.aliens.dms.domain.outing.spi.vo.OutingCompanionVO

class QueryOutingCompanionVO @QueryProjection constructor(
studentName: String?,
studentGrade: Int?,
studentClassRoom: Int?,
studentNumber: Int?
) : OutingCompanionVO(
studentName = studentName ?: "",
studentGrade = studentGrade ?: 0,
studentClassRoom = studentClassRoom ?: 0,
studentNumber = studentNumber ?: 0
)
Loading

0 comments on commit d585fa4

Please sign in to comment.