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

refactor: 발급 티켓 도메인 메서드 정리 및 API 추가 #180

Merged
merged 4 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@


import band.gosrock.api.issuedTicket.dto.response.RetrieveIssuedTicketListResponse;
import band.gosrock.api.issuedTicket.service.EntranceIssuedTicketUseCase;
import band.gosrock.api.issuedTicket.service.ReadIssuedTicketsUseCase;
import band.gosrock.domain.common.vo.IssuedTicketInfoVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -21,6 +25,8 @@ public class AdminIssuedTicketController {

private final ReadIssuedTicketsUseCase readIssuedTicketsUseCase;

private final EntranceIssuedTicketUseCase entranceIssuedTicketUseCase;

@Operation(summary = "[어드민 기능] 발급 티켓 리스트 가져오기 API 입니다.")
@GetMapping
public RetrieveIssuedTicketListResponse getIssuedTickets(
Expand All @@ -30,4 +36,10 @@ public RetrieveIssuedTicketListResponse getIssuedTickets(
@RequestParam(required = false) String phoneNumber) {
return readIssuedTicketsUseCase.execute(page, eventId, userName, phoneNumber);
}

@Operation(summary = "[어드민 기능] 발급 티켓 입장 처리 API 입니다.")
@PatchMapping(value = "/{issuedTicketId}")
public IssuedTicketInfoVo patchIssuedTicketStatus(@PathVariable Long issuedTicketId) {
return entranceIssuedTicketUseCase.execute(issuedTicketId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ public RetrieveIssuedTicketListResponse toIssuedTicketPageResponse(
public RetrieveIssuedTicketDetailResponse toIssuedTicketDetailResponse(
Long currentUserId, Long issuedTicketId) {
return RetrieveIssuedTicketDetailResponse.of(
issuedTicketAdaptor.find(currentUserId, issuedTicketId));
issuedTicketAdaptor.findForUser(currentUserId, issuedTicketId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package band.gosrock.api.issuedTicket.service;


import band.gosrock.api.common.UserUtils;
import band.gosrock.api.issuedTicket.mapper.IssuedTicketMapper;
import band.gosrock.common.annotation.UseCase;
import band.gosrock.domain.common.vo.IssuedTicketInfoVo;
import band.gosrock.domain.domains.issuedTicket.service.IssuedTicketDomainService;
import lombok.RequiredArgsConstructor;

@UseCase
@RequiredArgsConstructor
public class EntranceIssuedTicketUseCase {

private final IssuedTicketDomainService issuedTicketDomainService;

private final IssuedTicketMapper issuedTicketMapper;

private final UserUtils userUtils;

public IssuedTicketInfoVo execute(Long issuedTicketId) {
Long currentUserId = userUtils.getCurrentUserId();
return issuedTicketDomainService.processingEntranceIssuedTicket(
currentUserId, issuedTicketId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public List<IssuedTicket> findAllByOrderLineId(Long orderLineId) {
return issuedTicketRepository.findAllByOrderLineId(orderLineId);
}

public IssuedTicket find(Long currentUserId, Long issuedTicketId) {
public IssuedTicket findForUser(Long currentUserId, Long issuedTicketId) {
IssuedTicket issuedTicket =
issuedTicketRepository
.find(issuedTicketId)
Expand All @@ -43,14 +43,20 @@ public IssuedTicket find(Long currentUserId, Long issuedTicketId) {
return issuedTicket;
}

public IssuedTicket find(Long issuedTicketId) {
return issuedTicketRepository
.find(issuedTicketId)
.orElseThrow(() -> IssuedTicketNotFoundException.EXCEPTION);
}

public Page<IssuedTicket> searchIssuedTicket(Long page, IssuedTicketCondition condition) {
PageRequest pageRequest =
PageRequest.of(Math.toIntExact(page), 10, Sort.by("id").descending());
return issuedTicketRepository.searchToPage(condition, pageRequest);
}

public void delete(IssuedTicket issuedTicket) {
issuedTicket.cancelIssuedTicket();
issuedTicket.cancel();
}
Copy link
Member

Choose a reason for hiding this comment

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

cancel 로 통일시키는게 좋아보입니당!


public List<IssuedTicket> findAllByOrderUuid(String orderUuid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
import band.gosrock.domain.domains.event.domain.Event;
import band.gosrock.domain.domains.issuedTicket.dto.request.CreateIssuedTicketDTO;
import band.gosrock.domain.domains.issuedTicket.dto.response.CreateIssuedTicketResponse;
import band.gosrock.domain.domains.issuedTicket.exception.CanNotCancelEntranceException;
import band.gosrock.domain.domains.issuedTicket.exception.CanNotCancelException;
import band.gosrock.domain.domains.issuedTicket.exception.CanNotEntranceException;
import band.gosrock.domain.domains.issuedTicket.exception.IssuedTicketAlreadyEntranceException;
import band.gosrock.domain.domains.ticket_item.domain.TicketItem;
import band.gosrock.domain.domains.user.domain.User;
import java.util.ArrayList;
Expand Down Expand Up @@ -57,7 +61,6 @@ public class IssuedTicket extends BaseTimeEntity {

/*
발급 티켓의 주문 행 (단방향)
Todo: 발급 티켓이 굳이 order line 을 알아야 할까? -찬진 OrderResponse 에서 필요함! 연관관계는 따로안짓고 레지스터리에서 불러올게용ㄴ
*/
private Long orderLineId;

Expand Down Expand Up @@ -98,7 +101,7 @@ public void addOptionAnswers(List<IssuedTicketOptionAnswer> answers) {
private Money price;

/*
상태
발급 티켓 상태
*/
@Enumerated(EnumType.STRING)
private IssuedTicketStatus issuedTicketStatus = IssuedTicketStatus.ENTRANCE_INCOMPLETE;
Expand Down Expand Up @@ -127,6 +130,11 @@ public IssuedTicket(
this.issuedTicketOptionAnswers.addAll(issuedTicketOptionAnswers);
}

/** ---------------------------- 생성 관련 메서드 ---------------------------------- */

/*
개발 및 테스트 용도로 사용되는 티켓 발급 정적 메서드
*/
public static IssuedTicket createForDev(
Event event,
User user,
Expand All @@ -149,16 +157,25 @@ public static IssuedTicket createForDev(
return createIssuedTicket;
}

/*
issuedTicket 생성하면서 UUID 생성
*/
@PrePersist
public void createUUID() {
this.uuid = UUID.randomUUID().toString();
}

/*
issuedTicket 생성하면서 티켓 넘버 부여
*/
@PostPersist
public void createIssuedTicketNo() {
this.issuedTicketNo = "T" + Long.sum(NO_START_NUMBER, this.id);
}

/*
발급 티켓 옵션들 합 계산
*/
public Money sumOptionPrice() {
return issuedTicketOptionAnswers.stream()
.map(
Expand All @@ -167,10 +184,16 @@ public Money sumOptionPrice() {
.reduce(Money.ZERO, Money::plus);
}

/*
issuedTicket VO 변환 메서드
*/
public IssuedTicketInfoVo toIssuedTicketInfoVo() {
return IssuedTicketInfoVo.from(this);
}

/*
orderLine -> issuedTicket 생성 메서드
*/
public static CreateIssuedTicketResponse orderLineItemToIssuedTickets(
CreateIssuedTicketDTO dto) {
long quantity = dto.getOrderLineItem().getQuantity();
Expand All @@ -196,7 +219,41 @@ public static CreateIssuedTicketResponse orderLineItemToIssuedTickets(
return new CreateIssuedTicketResponse(createIssuedTickets, issuedTicketOptionAnswers);
}

public void cancelIssuedTicket() {
/** ---------------------------- 상태 변환 관련 메서드 ---------------------------------- */

/*
발급 티켓 취소 메서드
티켓이 입장 미완료 상태가 아니면 취소 할 수 없음
*/
public void cancel() {
if (this.issuedTicketStatus != IssuedTicketStatus.ENTRANCE_INCOMPLETE) {
throw CanNotCancelException.EXCEPTION;
}
this.issuedTicketStatus = IssuedTicketStatus.CANCELED;
}

/*
발급 티켓으로 입장 시 상태 변환 메서드
티켓이 입장 미완료 상태가 아니면 입장 할 수 없음
*/
public void entrance() {
if (this.issuedTicketStatus == IssuedTicketStatus.CANCELED) {
Copy link
Member

Choose a reason for hiding this comment

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

백기선 님 강좌듣는데 이넘값을 == 으로 비교하면 더 좋다 그러더라구요
this.issuedTicketStatus.equals(IssuedTicketStatus.CANCELED)
위방식보다
민준님 방식이 euqals 칠때 null 포인터 exception 까지 막을수 있으니

throw CanNotEntranceException.EXCEPTION;
}
if (this.issuedTicketStatus == IssuedTicketStatus.ENTRANCE_COMPLETED) {
throw IssuedTicketAlreadyEntranceException.EXCEPTION;
}
this.issuedTicketStatus = IssuedTicketStatus.ENTRANCE_COMPLETED;
}

/*
입장 처리 취소 메서드
티켓이 입장 완료 상태가 아니면 입장 취소 할 수 없음
*/
public void entranceCancel() {
if (this.issuedTicketStatus != IssuedTicketStatus.ENTRANCE_COMPLETED) {
throw CanNotCancelEntranceException.EXCEPTION;
}
this.issuedTicketStatus = IssuedTicketStatus.ENTRANCE_INCOMPLETE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package band.gosrock.domain.domains.issuedTicket.exception;


import band.gosrock.common.exception.DuDoongCodeException;

public class CanNotCancelEntranceException extends DuDoongCodeException {

public static final DuDoongCodeException EXCEPTION = new CanNotCancelEntranceException();

private CanNotCancelEntranceException() {
super(IssuedTicketErrorCode.CAN_NOT_CANCEL_ENTRANCE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package band.gosrock.domain.domains.issuedTicket.exception;


import band.gosrock.common.exception.DuDoongCodeException;

public class CanNotCancelException extends DuDoongCodeException {

public static final DuDoongCodeException EXCEPTION = new CanNotCancelException();

private CanNotCancelException() {
super(IssuedTicketErrorCode.CAN_NOT_CANCEL);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package band.gosrock.domain.domains.issuedTicket.exception;


import band.gosrock.common.exception.DuDoongCodeException;

public class CanNotEntranceException extends DuDoongCodeException {

public static final DuDoongCodeException EXCEPTION = new CanNotEntranceException();

private CanNotEntranceException() {
super(IssuedTicketErrorCode.CAN_NOT_ENTRANCE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package band.gosrock.domain.domains.issuedTicket.exception;


import band.gosrock.common.exception.DuDoongCodeException;

public class IssuedTicketAlreadyEntranceException extends DuDoongCodeException {

public static final DuDoongCodeException EXCEPTION = new IssuedTicketAlreadyEntranceException();

private IssuedTicketAlreadyEntranceException() {
super(IssuedTicketErrorCode.ISSUED_TICKET_ALREADY_ENTRANCE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
public enum IssuedTicketErrorCode implements BaseErrorCode {
ISSUED_TICKET_NOT_FOUND(NOT_FOUND, "IssuedTicket_404_1", "IssuedTicket Not Found"),
ISSUED_TICKET_NOT_MATCHED_USER(
BAD_REQUEST, "IssuedTicket_400_1", "IssuedTicket User Not Matched");
BAD_REQUEST, "IssuedTicket_400_1", "IssuedTicket User Not Matched"),
CAN_NOT_CANCEL(BAD_REQUEST, "IssuedTicket_400_2", "티켓을 취소 할 수 있는 상태가 아닙니다."),
CAN_NOT_CANCEL_ENTRANCE(BAD_REQUEST, "IssuedTicket_400_3", "티켓이 입장 취소 할 수 있는 상태가 아닙니다."),
CAN_NOT_ENTRANCE(BAD_REQUEST, "IssuedTicket_400_4", "티켓이 입장 할 수 있는 상태가 아닙니다."),
ISSUED_TICKET_ALREADY_ENTRANCE(BAD_REQUEST, "IssuedTicket_400_5", "이미 입장 처리된 티켓입니다.");

private Integer status;
private String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

import band.gosrock.common.annotation.DomainService;
import band.gosrock.domain.common.aop.redissonLock.RedissonLock;
import band.gosrock.domain.common.vo.IssuedTicketInfoVo;
import band.gosrock.domain.domains.event.adaptor.EventAdaptor;
import band.gosrock.domain.domains.event.exception.HostNotAuthEventException;
import band.gosrock.domain.domains.issuedTicket.adaptor.IssuedTicketAdaptor;
import band.gosrock.domain.domains.issuedTicket.adaptor.IssuedTicketOptionAnswerAdaptor;
import band.gosrock.domain.domains.issuedTicket.domain.IssuedTicket;
Expand All @@ -12,6 +14,7 @@
import band.gosrock.domain.domains.issuedTicket.repository.IssuedTicketRepository;
import band.gosrock.domain.domains.ticket_item.domain.TicketItem;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -25,11 +28,7 @@ public class IssuedTicketDomainService {
private final IssuedTicketOptionAnswerAdaptor issuedTicketOptionAnswerAdaptor;
private final EventAdaptor eventAdaptor;

@RedissonLock(
LockName = "티켓재고관리",
paramClassType = TicketItem.class,
identifier = "id",
needSameTransaction = true)
@RedissonLock(LockName = "티켓재고관리", paramClassType = TicketItem.class, identifier = "id")
@Transactional
public void createIssuedTicket(
TicketItem ticketItem, List<CreateIssuedTicketDTO> createIssuedTicketDTOs) {
Expand All @@ -41,11 +40,7 @@ public void createIssuedTicket(
});
}

@RedissonLock(
LockName = "티켓재고관리",
paramClassType = TicketItem.class,
identifier = "id",
needSameTransaction = true)
@RedissonLock(LockName = "티켓재고관리", paramClassType = TicketItem.class, identifier = "id")
@Transactional
public void withDrawIssuedTicket(TicketItem ticketItem, List<IssuedTicket> issuedTickets) {
issuedTickets.forEach(
Expand All @@ -54,4 +49,15 @@ public void withDrawIssuedTicket(TicketItem ticketItem, List<IssuedTicket> issue
issuedTicketAdaptor.delete(issuedTicket);
});
}

@Transactional
public IssuedTicketInfoVo processingEntranceIssuedTicket(
Long currentUserId, Long issuedTicketId) {
IssuedTicket issuedTicket = issuedTicketAdaptor.find(issuedTicketId);
if (!Objects.equals(issuedTicket.getEvent().getHostId(), currentUserId)) {
throw HostNotAuthEventException.EXCEPTION;
}
issuedTicket.entrance();
return issuedTicket.toIssuedTicketInfoVo();
}
}