diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveController.kt index 869dd19..9e040bd 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveController.kt @@ -15,6 +15,10 @@ import org.springframework.web.multipart.MultipartFile @RestController @RequestMapping("/admin/live") class AdminLiveController(private val service: AdminLiveService) { + @PostMapping("/cancel-not-started") + @PreAuthorize("hasRole('BOT')") + fun cancelNotStartedLive4hoursPassed() = ApiResponse.ok(service.cancelNotStartedLive4hoursPassed()) + @GetMapping @PreAuthorize("hasRole('ADMIN')") fun getOnAirLive() = ApiResponse.ok(data = service.getLiveList()) @@ -24,6 +28,7 @@ class AdminLiveController(private val service: AdminLiveService) { fun getRecommendCreatorBanner(pageable: Pageable) = ApiResponse.ok(service.getRecommendCreator(pageable)) @PostMapping("/recommend-creator") + @PreAuthorize("hasRole('ADMIN')") fun createRecommendCreatorBanner( @RequestParam("image") image: MultipartFile, @RequestParam("creator_id") creatorId: Long, @@ -36,6 +41,7 @@ class AdminLiveController(private val service: AdminLiveService) { ) @PutMapping("/recommend-creator") + @PreAuthorize("hasRole('ADMIN')") fun updateRecommendCreatorBanner( @RequestParam("recommend_creator_banner_id") recommendCreatorBannerId: Long, @RequestParam("image", required = false) image: MultipartFile?, @@ -49,6 +55,7 @@ class AdminLiveController(private val service: AdminLiveService) { ) @PutMapping("/recommend-creator/orders") + @PreAuthorize("hasRole('ADMIN')") fun updateRecommendCreatorBannerOrders( @RequestBody request: UpdateAdminRecommendCreatorBannerOrdersRequest ) = ApiResponse.ok( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveRoomQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveRoomQueryRepository.kt index dbc2890..3b435c9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveRoomQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveRoomQueryRepository.kt @@ -8,6 +8,7 @@ import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom import kr.co.vividnext.sodalive.member.QMember.member import org.springframework.data.domain.Pageable import org.springframework.stereotype.Repository +import java.time.LocalDateTime @Repository class AdminLiveRoomQueryRepository(private val queryFactory: JPAQueryFactory) { @@ -36,4 +37,15 @@ class AdminLiveRoomQueryRepository(private val queryFactory: JPAQueryFactory) { .orderBy(recommendLiveCreatorBanner.orders.asc(), recommendLiveCreatorBanner.id.desc()) .fetch() } + + fun getNotStartedLive4hoursPassed(): List { + return queryFactory + .selectFrom(liveRoom) + .where( + liveRoom.isActive.isTrue + .and(liveRoom.channelName.isNotNull) + .and(liveRoom.beginDateTime.loe(LocalDateTime.now().minusHours(12))) + ) + .fetch() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt index 0865230..de78852 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt @@ -2,12 +2,28 @@ package kr.co.vividnext.sodalive.admin.live import com.amazonaws.services.s3.model.ObjectMetadata import kr.co.vividnext.sodalive.aws.s3.S3Uploader +import kr.co.vividnext.sodalive.can.CanRepository +import kr.co.vividnext.sodalive.can.charge.Charge +import kr.co.vividnext.sodalive.can.charge.ChargeRepository +import kr.co.vividnext.sodalive.can.charge.ChargeStatus +import kr.co.vividnext.sodalive.can.payment.Payment +import kr.co.vividnext.sodalive.can.payment.PaymentGateway +import kr.co.vividnext.sodalive.can.payment.PaymentStatus +import kr.co.vividnext.sodalive.can.use.CanUsage +import kr.co.vividnext.sodalive.can.use.UseCanCalculateRepository +import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.fcm.FcmEvent +import kr.co.vividnext.sodalive.fcm.FcmEventType import kr.co.vividnext.sodalive.live.recommend.RecommendLiveCreatorBanner import kr.co.vividnext.sodalive.live.recommend.RecommendLiveCreatorBannerRepository +import kr.co.vividnext.sodalive.live.reservation.LiveReservationRepository +import kr.co.vividnext.sodalive.live.room.cancel.LiveRoomCancel +import kr.co.vividnext.sodalive.live.room.cancel.LiveRoomCancelRepository import kr.co.vividnext.sodalive.member.MemberRepository import kr.co.vividnext.sodalive.utils.generateFileName import org.springframework.beans.factory.annotation.Value +import org.springframework.context.ApplicationEventPublisher import org.springframework.data.domain.Pageable import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @@ -20,10 +36,18 @@ import java.time.format.DateTimeFormatter @Service class AdminLiveService( private val recommendCreatorBannerRepository: RecommendLiveCreatorBannerRepository, + private val roomCancelRepository: LiveRoomCancelRepository, private val repository: AdminLiveRoomQueryRepository, private val memberRepository: MemberRepository, private val s3Uploader: S3Uploader, + private val useCanCalculateRepository: UseCanCalculateRepository, + private val reservationRepository: LiveReservationRepository, + private val chargeRepository: ChargeRepository, + private val canRepository: CanRepository, + + private val applicationEventPublisher: ApplicationEventPublisher, + @Value("\${cloud.aws.s3.bucket}") private val bucket: String, @Value("\${cloud.aws.cloud-front.host}") @@ -237,4 +261,69 @@ class AdminLiveService( } } } + + @Transactional + fun cancelNotStartedLive4hoursPassed() { + val findRoomList = repository.getNotStartedLive4hoursPassed() + + for (room in findRoomList) { + room.isActive = false + + val roomCancel = LiveRoomCancel("관리자에 의한 취소 - 노쇼") + roomCancel.room = room + roomCancelRepository.save(roomCancel) + + // 유료방인 경우 환불처리 + if (room.price > 0) { + val bookerList = reservationRepository.getReservationBookerList(roomId = room.id!!) + for (booker in bookerList) { + val useCan = canRepository.getCanUsedForLiveRoomNotRefund( + memberId = booker.id!!, + roomId = room.id!!, + canUsage = CanUsage.LIVE + ) ?: continue + useCan.isRefund = true + + val useCanCalculate = useCanCalculateRepository.findByUseCanIdAndStatus(useCanId = useCan.id!!) + useCanCalculate.forEach { + it.status = UseCanCalculateStatus.REFUND + + val charge = Charge(0, it.can, status = ChargeStatus.REFUND_CHARGE) + charge.title = "${it.can} 캔" + charge.useCan = useCan + + when (it.paymentGateway) { + PaymentGateway.PG -> booker.pgRewardCan += charge.rewardCan + PaymentGateway.GOOGLE_IAP -> booker.googleRewardCan += charge.rewardCan + PaymentGateway.APPLE_IAP -> booker.appleRewardCan += charge.rewardCan + } + charge.member = booker + + val payment = Payment( + status = PaymentStatus.COMPLETE, + paymentGateway = it.paymentGateway + ) + payment.method = "환불" + charge.payment = payment + + chargeRepository.save(charge) + } + } + } + + // 예약현황 취소 + val pushTokenListMap = memberRepository.getPushTokenFromReservationList(room.id!!) + reservationRepository.cancelReservation(roomId = room.id!!) + + // 라이브 취소 푸시 발송 + applicationEventPublisher.publishEvent( + FcmEvent( + type = FcmEventType.CANCEL_LIVE, + title = room.member!!.nickname, + message = "라이브 취소 : ${room.title}", + recipientsMap = pushTokenListMap + ) + ) + } + } }