Skip to content

Commit

Permalink
feat: 학교 인증이 완료된 학생만 재학생용 티켓 예매 가능하도록 하는 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
xxeol2 committed Sep 21, 2023
1 parent 2486eb5 commit 454bbba
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum ErrorCode {
INVALID_TICKET_CREATE_TIME("티켓 예매 시작 후 새롭게 티켓을 발급할 수 없습니다."),
OAUTH2_NOT_SUPPORTED_SOCIAL_TYPE("해당 OAuth2 제공자는 지원되지 않습니다."),
RESERVE_TICKET_OVER_AMOUNT("예매 가능한 수량을 초과했습니다."),
NEED_STUDENT_VERIFICATION("학생 인증이 필요합니다."),
OAUTH2_INVALID_TOKEN("잘못된 OAuth2 토큰입니다."),
ALREADY_STUDENT_VERIFIED("이미 학교 인증이 완료된 사용자입니다."),
DUPLICATE_STUDENT_EMAIL("이미 인증된 이메일입니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.festago.student.repository;

import com.festago.member.domain.Member;
import com.festago.school.domain.School;
import com.festago.student.domain.Student;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student, Long> {

boolean existsByMemberAndSchool(Member member, School school);

boolean existsByUsernameAndSchoolId(String username, Long id);

boolean existsByMemberId(Long id);
Expand Down
4 changes: 4 additions & 0 deletions backend/src/main/java/com/festago/ticket/domain/Ticket.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ public Stage getStage() {
return stage;
}

public School getSchool() {
return school;
}

public TicketType getTicketType() {
return ticketType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public interface TicketRepository extends JpaRepository<Ticket, Long> {
SELECT t FROM Ticket t
JOIN FETCH t.stage s
JOIN FETCH t.ticketEntryTimes et
JOIN FETCH t.school sc
WHERE t.id = :ticketId
""")
Optional<Ticket> findByIdWithFetch(@Param("ticketId") Long ticketId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import com.festago.common.exception.NotFoundException;
import com.festago.member.domain.Member;
import com.festago.member.repository.MemberRepository;
import com.festago.student.repository.StudentRepository;
import com.festago.ticket.domain.Ticket;
import com.festago.ticket.domain.TicketAmount;
import com.festago.ticket.domain.TicketType;
import com.festago.ticket.repository.TicketAmountRepository;
import com.festago.ticket.repository.TicketRepository;
import com.festago.ticketing.domain.MemberTicket;
Expand All @@ -26,28 +28,41 @@ public class TicketingService {
private final TicketAmountRepository ticketAmountRepository;
private final TicketRepository ticketRepository;
private final MemberRepository memberRepository;
private final StudentRepository studentRepository;
private final Clock clock;

public TicketingService(MemberTicketRepository memberTicketRepository,
TicketAmountRepository ticketAmountRepository,
TicketRepository ticketRepository, MemberRepository memberRepository, Clock clock) {
TicketRepository ticketRepository, MemberRepository memberRepository,
StudentRepository studentRepository, Clock clock) {
this.memberTicketRepository = memberTicketRepository;
this.ticketAmountRepository = ticketAmountRepository;
this.ticketRepository = ticketRepository;
this.memberRepository = memberRepository;
this.studentRepository = studentRepository;
this.clock = clock;
}

public TicketingResponse ticketing(Long memberId, TicketingRequest request) {
Ticket ticket = findTicketById(request.ticketId());
Member member = findMemberById(memberId);
validateAlreadyReserved(member, ticket);
validateStudent(member, ticket);
int reserveSequence = getReserveSequence(request.ticketId());
MemberTicket memberTicket = ticket.createMemberTicket(member, reserveSequence, LocalDateTime.now(clock));
memberTicketRepository.save(memberTicket);
return TicketingResponse.from(memberTicket);
}

private void validateStudent(Member member, Ticket ticket) {
if (ticket.getTicketType() != TicketType.STUDENT) {
return;
}
if (!studentRepository.existsByMemberAndSchool(member, ticket.getSchool())) {
throw new BadRequestException(ErrorCode.NEED_STUDENT_VERIFICATION);
}
}

private Ticket findTicketById(Long ticketId) {
return ticketRepository.findByIdWithFetch(ticketId)
.orElseThrow(() -> new NotFoundException(ErrorCode.TICKET_NOT_FOUND));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.festago.ticketing.application;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.BDDMockito.given;

import com.festago.common.exception.BadRequestException;
import com.festago.member.domain.Member;
import com.festago.member.repository.MemberRepository;
import com.festago.school.domain.School;
import com.festago.stage.domain.Stage;
import com.festago.student.repository.StudentRepository;
import com.festago.support.MemberFixture;
import com.festago.support.TicketFixture;
import com.festago.ticket.domain.TicketType;
import com.festago.ticket.repository.TicketAmountRepository;
import com.festago.ticket.repository.TicketRepository;
import com.festago.ticketing.dto.TicketingRequest;
import com.festago.ticketing.repository.MemberTicketRepository;
import java.time.Clock;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator.ReplaceUnderscores;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
@DisplayNameGeneration(ReplaceUnderscores.class)
@SuppressWarnings("NonAsciiCharacters")
class TicketingServiceTest {

@Mock
MemberTicketRepository memberTicketRepository;

@Mock
TicketAmountRepository ticketAmountRepository;

@Mock
TicketRepository ticketRepository;

@Mock
MemberRepository memberRepository;

@Mock
StudentRepository studentRepository;

@Spy
Clock clock = Clock.systemDefaultZone();

@InjectMocks
TicketingService ticketingService;

@BeforeEach
void setUp() {

}

@Test
void 재학생용_티켓인데_학생인증이_되지_않았으면_예외() {
// given
TicketingRequest request = new TicketingRequest(1L);
given(memberRepository.findById(anyLong()))
.willReturn(Optional.of(MemberFixture.member().build()));
given(memberTicketRepository.existsByOwnerAndStage(any(Member.class), any(Stage.class)))
.willReturn(false);

given(ticketRepository.findByIdWithFetch(anyLong()))
.willReturn(Optional.of(TicketFixture.ticket().ticketType(TicketType.STUDENT).build()));
given(studentRepository.existsByMemberAndSchool(any(Member.class), any(School.class)))
.willReturn(false);

// when & then
assertThatThrownBy(() -> ticketingService.ticketing(1L, request))
.isInstanceOf(BadRequestException.class)
.hasMessage("학생 인증이 필요합니다.");
}
}

0 comments on commit 454bbba

Please sign in to comment.