Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] #172 - promotion 필드 추가 및 지난 공연 캐러샐 자동 삭제 구현, response에 dueDate 추가 #175

Merged
merged 9 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/com/beat/BeatApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableFeignClients
@EnableScheduling
@ImportAutoConfiguration({FeignAutoConfiguration.class})
public class BeatApplication {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

Expand All @@ -58,11 +59,17 @@ public PerformanceDetailResponse getPerformanceDetail(Long performanceId) {
.orElseThrow(() -> new NotFoundException(PerformanceErrorCode.PERFORMANCE_NOT_FOUND));

List<PerformanceDetailSchedule> scheduleList = scheduleRepository.findByPerformanceId(performanceId).stream()
.map(schedule -> PerformanceDetailSchedule.of(
schedule.getId(),
schedule.getPerformanceDate(),
schedule.getScheduleNumber().name()
)).collect(Collectors.toList());
.map(schedule -> {
int dueDate = scheduleService.calculateDueDate(schedule);
return PerformanceDetailSchedule.of(
schedule.getId(),
schedule.getPerformanceDate(),
schedule.getScheduleNumber().name(),
dueDate
);
}).collect(Collectors.toList());

int minDueDate = scheduleService.getMinDueDate(scheduleRepository.findAllByPerformanceId(performanceId));

List<PerformanceDetailCast> castList = castRepository.findByPerformanceId(performanceId).stream()
.map(cast -> PerformanceDetailCast.of(
Expand Down Expand Up @@ -95,7 +102,8 @@ public PerformanceDetailResponse getPerformanceDetail(Long performanceId) {
performance.getPerformanceContact(),
performance.getPerformanceTeamName(),
castList,
staffList
staffList,
minDueDate
);
}

Expand All @@ -107,12 +115,14 @@ public BookingPerformanceDetailResponse getBookingPerformanceDetail(Long perform
List<BookingPerformanceDetailSchedule> scheduleList = scheduleRepository.findByPerformanceId(performanceId).stream()
.map(schedule -> {
scheduleService.updateBookingStatus(schedule);
int dueDate = scheduleService.calculateDueDate(schedule);
return BookingPerformanceDetailSchedule.of(
schedule.getId(),
schedule.getPerformanceDate(),
schedule.getScheduleNumber().name(),
scheduleService.getAvailableTicketCount(schedule),
schedule.isBooking()
schedule.isBooking(),
dueDate
);
}).collect(Collectors.toList());

Expand Down Expand Up @@ -206,18 +216,40 @@ public MakerPerformanceResponse getMemberPerformances(Long memberId) {
List<Performance> performances = performanceRepository.findByUsersId(user.getId());

List<MakerPerformanceDetail> performanceDetails = performances.stream()
.map(performance -> MakerPerformanceDetail.of(
performance.getId(),
performance.getGenre().name(),
performance.getPerformanceTitle(),
performance.getPosterImage(),
performance.getPerformancePeriod()
))
.map(performance -> {
List<Schedule> schedules = scheduleRepository.findByPerformanceId(performance.getId());
int minDueDate = scheduleService.getMinDueDate(schedules);

return MakerPerformanceDetail.of(
performance.getId(),
performance.getGenre().name(),
performance.getPerformanceTitle(),
performance.getPosterImage(),
performance.getPerformancePeriod(),
minDueDate
);
})
.collect(Collectors.toList());

return MakerPerformanceResponse.of(user.getId(), performanceDetails);
// 양수 minDueDate 정렬
List<MakerPerformanceDetail> positiveDueDates = performanceDetails.stream()
.filter(detail -> detail.minDueDate() >= 0)
.sorted(Comparator.comparingInt(MakerPerformanceDetail::minDueDate))
.collect(Collectors.toList());

// 음수 minDueDate 정렬
List<MakerPerformanceDetail> negativeDueDates = performanceDetails.stream()
.filter(detail -> detail.minDueDate() < 0)
.sorted(Comparator.comparingInt(MakerPerformanceDetail::minDueDate).reversed())
.collect(Collectors.toList());

// 병합된 리스트
positiveDueDates.addAll(negativeDueDates);

return MakerPerformanceResponse.of(user.getId(), positiveDueDates);
}


@Transactional
public PerformanceEditResponse getPerformanceEdit(Long memberId, Long performanceId) {
Member member = memberRepository.findById(memberId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ public record BookingPerformanceDetailSchedule(
LocalDateTime performanceDate,
String scheduleNumber,
int availableTicketCount,
boolean isBooking
boolean isBooking,
int dueDate
) {
public static BookingPerformanceDetailSchedule of(Long scheduleId, LocalDateTime performanceDate, String scheduleNumber, int availableTicketCount, boolean isBooking) {
return new BookingPerformanceDetailSchedule(scheduleId, performanceDate, scheduleNumber, availableTicketCount, isBooking);
public static BookingPerformanceDetailSchedule of(Long scheduleId, LocalDateTime performanceDate, String scheduleNumber, int availableTicketCount, boolean isBooking, int dueDate) {
return new BookingPerformanceDetailSchedule(scheduleId, performanceDate, scheduleNumber, availableTicketCount, isBooking, dueDate);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ public record MakerPerformanceDetail(
String genre,
String performanceTitle,
String posterImage,
String performancePeriod
String performancePeriod,
int minDueDate
) {
public static MakerPerformanceDetail of(
Long performanceId,
String genre,
String performanceTitle,
String posterImage,
String performancePeriod) {
return new MakerPerformanceDetail(performanceId, genre, performanceTitle, posterImage, performancePeriod);
String performancePeriod,
int minDueDate) { // minDueDate 매개변수 추가
return new MakerPerformanceDetail(performanceId, genre, performanceTitle, posterImage, performancePeriod, minDueDate);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public record PerformanceDetailResponse(
String performanceContact,
String performanceTeamName,
List<PerformanceDetailCast> castList,
List<PerformanceDetailStaff> staffList
List<PerformanceDetailStaff> staffList,
int minDueDate
) {
public static PerformanceDetailResponse of(
Long performanceId,
Expand All @@ -34,10 +35,26 @@ public static PerformanceDetailResponse of(
String performanceContact,
String performanceTeamName,
List<PerformanceDetailCast> castList,
List<PerformanceDetailStaff> staffList
List<PerformanceDetailStaff> staffList,
int minDueDate
) {
return new PerformanceDetailResponse(performanceId, performanceTitle, performancePeriod, scheduleList, ticketPrice, genre, posterImage, runningTime, performanceVenue, performanceDescription, performanceAttentionNote, performanceContact, performanceTeamName, castList, staffList);
return new PerformanceDetailResponse(
performanceId,
Comment on lines +41 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 공백 제거 부탁드릴게요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    return new PerformanceDetailResponse(performanceId, performanceTitle, performancePeriod, scheduleList, ticketPrice, genre, posterImage, runningTime, performanceVenue, performanceDescription, performanceAttentionNote, performanceContact, performanceTeamName, castList, staffList, minDueDate);

이런 식으로 공백 제거 말씀하시는 거 맞을까요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

아뇨 ㅎㅎㅎ

이런식으로 줄바꿈이 3번 되어있어서 말씀드린 겁니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엇 제 코드 상으론 공백 없는 채로 커밋했는데 왜 이렇게 보일까요ㅠㅠ 다시 커밋해보겠습니다

performanceTitle,
performancePeriod,
scheduleList,
ticketPrice,
genre,
posterImage,
runningTime,
performanceVenue,
performanceDescription,
performanceAttentionNote,
performanceContact,
performanceTeamName,
castList,
staffList,
minDueDate
);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
public record PerformanceDetailSchedule(
Long scheduleId,
LocalDateTime performanceDate,
String scheduleNumber
String scheduleNumber,
int dueDate
) {
public static PerformanceDetailSchedule of(Long scheduleId, LocalDateTime performanceDate, String scheduleNumber) {
return new PerformanceDetailSchedule(scheduleId, performanceDate, scheduleNumber);
public static PerformanceDetailSchedule of(Long scheduleId, LocalDateTime performanceDate, String scheduleNumber, int dueDate) {
return new PerformanceDetailSchedule(scheduleId, performanceDate, scheduleNumber, dueDate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.beat.domain.promotion.application;

import com.beat.domain.performance.domain.Performance;
import com.beat.domain.promotion.dao.PromotionRepository;
import com.beat.domain.promotion.domain.Promotion;
import com.beat.domain.schedule.application.ScheduleService;
import com.beat.domain.schedule.dao.ScheduleRepository;
import com.beat.domain.schedule.domain.Schedule;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
public class PromotionService {

private final PromotionRepository promotionRepository;
private final ScheduleRepository scheduleRepository;
private final ScheduleService scheduleService;

@Scheduled(cron = "1 0 0 * * ?")
@Transactional
public void checkAndDeleteInvalidPromotions() {
List<Promotion> promotions = promotionRepository.findAll();

for (Promotion promotion : promotions) {
if (promotion.getPerformance() != null) {
Performance performance = promotion.getPerformance();

List<Schedule> schedules = scheduleRepository.findByPerformanceId(performance.getId());
int minDueDate = scheduleService.getMinDueDate(schedules);

// MinDueDate가 음수일 경우 Promotion 삭제
if (minDueDate < 0) {
promotionRepository.delete(promotion);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

promotion.getPerformance() != null일 때 promotion.getPerformance()을 하는게 어색합니다.

우선순위가 promotion.getPerformance()을 한 후 null 체크를 하는게 맞을 것 같습니다!

코드를 아래와 같이 바꾸면 더 좋을 것 같다는 생각이 듭니다

@Scheduled(cron = "1 0 0 * * ?")
@Transactional
public void checkAndDeleteInvalidPromotions() {
    List<Promotion> promotions = promotionRepository.findAll();

    for (Promotion promotion : promotions) {
        Performance performance = promotion.getPerformance();
        if (performance != null) {
            List<Schedule> schedules = scheduleRepository.findByPerformanceId(performance.getId());
            int minDueDate = scheduleService.getMinDueDate(schedules);

            // MinDueDate가 음수일 경우 Promotion 삭제
            if (minDueDate < 0) {
                promotionRepository.delete(promotion);
            }
        }
    }
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

외부링크와 연결된 promotion의 경우 연관된 performance가 없기 때문에 먼저 performance를 저장하지 않고 null인지 체크 후 저장한 건데 그래도 바꾸는 게 더 낫다고 생각하시나요?

Copy link
Member

@hoonyworld hoonyworld Aug 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로직상은 둘다 문제가 없지만, 코드를 작성할때는 가독성과 유지보수성을 고려하여 설계를 하여야 합니다.

for문 바로 아래 if (promotion.getPerformance() != null) 로 공연이 null이 아닐 때 로직 수행을 하게 되는데, 이는 확장성이 부족한 코드라고 생각됩니다.

향후 다른 조건에 따라 프로모션을 처리해야 할 경우, 조건문이 계속해서 복잡해지고, 메서드의 가독성이 떨어질 수 있습니다.

private void processPromotion(Promotion promotion) {
    Performance performance = promotion.getPerformance();

    if (performance == null) {
        return; // performance가 null이면 메서드를 종료
    }

    List<Schedule> schedules = scheduleRepository.findByPerformanceId(performance.getId());
    int minDueDate = scheduleService.getMinDueDate(schedules);

    if (minDueDate < 0) {
        promotionRepository.delete(promotion);
    }
}

저는 위와 같은 방식으로 공연을 가져오고, null이면 얼리 리턴을 하는 방식을 추천드립니다.
향 후 null일 때, 처리로직이 변경되도 확장성을 고려해서 설계하였기 때문에 if문 안에 조건 블록 내에서 로직을 추가/변경하면 되겠습니다.

또한, 불필요한 중복을 줄일 수 있고, performance가 null이 아닌 경우에만 나머지 로직을 수행하기 때문에, 코드의 가독성이 더 좋아졌습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확실히 null일 경우 얼리 리턴 하는 방식이 효율적이고 확장성도 더 좋겠네요! 반영하겠습니다 감사합니다~~

}
}
}
}
16 changes: 13 additions & 3 deletions src/main/java/com/beat/domain/promotion/domain/Promotion.java
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

필드를 추가하면 테이블 컬럼 내용이 변경이 되야 하니, 직접 Dev, Prod DB에 칼럼을 추가해야 하는점 알고 계시면 좋을 것 같습니다!

제가 추가하는 법 알려드릴게요~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다ㅎㅎ

Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,29 @@ public class Promotion {
private String promotionPhoto;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "performance_id", nullable = false)
@JoinColumn(name = "performance_id", nullable = true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 공연 id 대신 외부 링크 url이 사용될 수 있어서 null=true로 설정하신거 맞을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞습니다!

private Performance performance;

@Column(nullable = true)
private String redirectUrl;

@Column(nullable = false)
private boolean isExternal;

@Builder
public Promotion(String promotionPhoto, Performance performance) {
public Promotion(String promotionPhoto, Performance performance, String redirectUrl, boolean isExternal) {
this.promotionPhoto = promotionPhoto;
this.performance = performance;
this.redirectUrl = redirectUrl;
this.isExternal = isExternal;
}

public static Promotion create(String promotionPhoto, Performance performance) {
public static Promotion create(String promotionPhoto, Performance performance, String redirectUrl, boolean isExternal) {
return Promotion.builder()
.promotionPhoto(promotionPhoto)
.performance(performance)
.redirectUrl(redirectUrl)
.isExternal(isExternal)
.build();
}
}
Loading