22
33import com .permitseoul .permitserver .domain .event .core .component .EventRetriever ;
44import com .permitseoul .permitserver .domain .event .core .domain .Event ;
5+ import com .permitseoul .permitserver .domain .event .core .exception .EventNotfoundException ;
56import com .permitseoul .permitserver .domain .payment .core .component .PaymentRetriever ;
67import com .permitseoul .permitserver .domain .payment .core .domain .Payment ;
7- import com .permitseoul .permitserver .domain .ticket .api .dto .EventTicketInfoResponse ;
8- import com .permitseoul .permitserver .domain .ticket .api .dto .UserBuyTicketInfo ;
8+ import com .permitseoul .permitserver .domain .ticket .api .dto .res .EventTicketInfoResponse ;
9+ import com .permitseoul .permitserver .domain .ticket .api .dto .res .UserBuyTicketInfoResponse ;
10+ import com .permitseoul .permitserver .domain .ticket .api .exception .ConflictTicketException ;
11+ import com .permitseoul .permitserver .domain .ticket .api .exception .DateTicketException ;
12+ import com .permitseoul .permitserver .domain .ticket .api .exception .IllegalTicketException ;
913import com .permitseoul .permitserver .domain .ticket .api .exception .NotFoundTicketException ;
1014import com .permitseoul .permitserver .domain .ticket .core .component .TicketRetriever ;
15+ import com .permitseoul .permitserver .domain .ticket .core .component .TicketUpdater ;
1116import com .permitseoul .permitserver .domain .ticket .core .domain .Ticket ;
1217import com .permitseoul .permitserver .domain .ticket .core .domain .TicketStatus ;
18+ import com .permitseoul .permitserver .domain .ticket .core .domain .entity .TicketEntity ;
19+ import com .permitseoul .permitserver .domain .ticket .core .exception .TicketNotFoundException ;
1320import com .permitseoul .permitserver .domain .ticketround .core .component .TicketRoundRetriever ;
1421import com .permitseoul .permitserver .domain .ticketround .core .domain .TicketRound ;
1522import com .permitseoul .permitserver .domain .tickettype .core .component .TicketTypeRetriever ;
@@ -41,6 +48,7 @@ public class TicketService {
4148 private final PaymentRetriever paymentRetriever ;
4249
4350 private static final String ORDER_DATE_FORMAT = "yyyy-MM-dd" ;
51+ private final TicketUpdater ticketUpdater ;
4452
4553 @ Transactional (readOnly = true )
4654 public EventTicketInfoResponse getEventTicketInfo (final long eventId , final LocalDateTime now ) {
@@ -75,14 +83,14 @@ public EventTicketInfoResponse getEventTicketInfo(final long eventId, final Loca
7583 }
7684
7785 @ Transactional (readOnly = true )
78- public UserBuyTicketInfo getUserBuyTicketInfo (final Long userId ) {
86+ public UserBuyTicketInfoResponse getUserBuyTicketInfo (final Long userId ) {
7987 if (userId == null ) {
80- return new UserBuyTicketInfo (List .of ());
88+ return new UserBuyTicketInfoResponse (List .of ());
8189 }
8290 try {
8391 final List <Ticket > ticketList = ticketRetriever .findAllTicketsByUserId (userId );
8492 if (ticketList .isEmpty ()) {
85- return new UserBuyTicketInfo (List .of ());
93+ return new UserBuyTicketInfoResponse (List .of ());
8694 }
8795
8896 final Map <Long , TicketType > ticketTypeMap = getTicketTypeMap (ticketList );
@@ -93,19 +101,61 @@ public UserBuyTicketInfo getUserBuyTicketInfo(final Long userId) {
93101
94102 final Map <String , BigDecimal > refundAmountByOrderId = findRefundAmountsFromPaymentIfAllTicketsCanceled (TicketListGroupedByOrderIdMap );
95103
96- final List <UserBuyTicketInfo .Order > orders = convertToOrderList (TicketListGroupedByOrderIdMap , eventMap , ticketTypeMap , refundAmountByOrderId );
104+ final List <UserBuyTicketInfoResponse .Order > orders = convertToOrderList (TicketListGroupedByOrderIdMap , eventMap , ticketTypeMap , refundAmountByOrderId );
97105
98- return new UserBuyTicketInfo (orders );
106+ return new UserBuyTicketInfoResponse (orders );
99107 } catch (TicketTypeNotfoundException e ) {
100108 throw new NotFoundTicketException (ErrorCode .NOT_FOUND_TICKET_TYPE );
101109 }
110+ }
111+
112+ @ Transactional
113+ public void confirmTicket (final String ticketCode , final String checkCodeFromTicket ) {
114+ try {
115+ final TicketEntity ticketEntity = ticketRetriever .findTicketEntityByTicketCode (ticketCode );
116+ verifyTicketStatus (ticketEntity .getStatus ());
117+
118+ final TicketType ticketType = ticketTypeRetriever .findTicketTypeById (ticketEntity .getTicketTypeId ());
119+ verifyTicketDate (ticketType .getTicketStartAt (), ticketType .getTicketEndAt ());
120+
121+ final Event event = eventRetriever .findEventById (ticketEntity .getEventId ());
122+ verifyTicketCheckCode (event .getTicketCheckCode (), checkCodeFromTicket );
123+
124+ ticketUpdater .updateTicketStatus (ticketEntity , TicketStatus .USED );
125+ } catch (TicketNotFoundException e ) {
126+ throw new NotFoundTicketException (ErrorCode .NOT_FOUND_TICKET );
127+ } catch (TicketTypeNotfoundException e ) {
128+ throw new NotFoundTicketException (ErrorCode .NOT_FOUND_TICKET_TYPE );
129+ } catch (EventNotfoundException e ) {
130+ throw new NotFoundTicketException (ErrorCode .NOT_FOUND_EVENT );
131+ }
132+ }
133+
134+ private void verifyTicketStatus (final TicketStatus ticketStatus ) {
135+ if (ticketStatus == TicketStatus .USED ) {
136+ throw new ConflictTicketException (ErrorCode .CONFLICT_ALREADY_USED_TICKET );
137+ } else if (ticketStatus == TicketStatus .CANCELED ) {
138+ throw new IllegalTicketException (ErrorCode .BAD_REQUEST_CANCELED_TICKET );
139+ }
140+ }
102141
142+ private void verifyTicketCheckCode (final String ticketCheckCode , final String checkCodeFromTicket ) {
143+ if (!Objects .equals (ticketCheckCode , checkCodeFromTicket )) {
144+ throw new IllegalTicketException (ErrorCode .BAD_REQUEST_TICKET_CHECK_CODE_ERROR );
145+ }
146+ }
147+
148+ private void verifyTicketDate (final LocalDateTime ticketStartAt , final LocalDateTime ticketEndAt ) {
149+ final LocalDateTime now = LocalDateTime .now ();
150+ if (now .isBefore (ticketStartAt ) || now .isAfter (ticketEndAt )) {
151+ throw new DateTicketException (ErrorCode .BAD_REQUEST_DATE_TIME_ERROR );
152+ }
103153 }
104154
105- private List <UserBuyTicketInfo .Order > convertToOrderList (final Map <String , List <Ticket >> ticketsGroupedByOrderId ,
106- final Map <Long , Event > eventMap ,
107- final Map <Long , TicketType > ticketTypeMap ,
108- final Map <String , BigDecimal > refundAmountByOrderId ) {
155+ private List <UserBuyTicketInfoResponse .Order > convertToOrderList (final Map <String , List <Ticket >> ticketsGroupedByOrderId ,
156+ final Map <Long , Event > eventMap ,
157+ final Map <Long , TicketType > ticketTypeMap ,
158+ final Map <String , BigDecimal > refundAmountByOrderId ) {
109159 return ticketsGroupedByOrderId .entrySet ().stream ()
110160 .map (entry -> {
111161 final String orderId = entry .getKey ();
@@ -117,12 +167,12 @@ private List<UserBuyTicketInfo.Order> convertToOrderList(final Map<String, List<
117167 final String eventName = eventMap .get (eventId ).getName ();
118168 final String eventVenue = eventMap .get (eventId ).getVenue ();
119169
120- final List <UserBuyTicketInfo .TicketInfo > ticketInfos = ticketsInOrder .stream ()
170+ final List <UserBuyTicketInfoResponse .TicketInfo > ticketInfos = ticketsInOrder .stream ()
121171 .map (ticket -> {
122172 final TicketType ticketType = ticketTypeMap .get (ticket .getTicketTypeId ());
123173 final boolean expired = isTicketDateExpired (ticketType .getTicketEndAt ());
124174
125- return new UserBuyTicketInfo .TicketInfo (
175+ return new UserBuyTicketInfoResponse .TicketInfo (
126176 ticket .getTicketCode (),
127177 ticketType .getTicketTypeName (),
128178 toUiStatus (ticket .getStatus (), expired ),
@@ -133,30 +183,30 @@ private List<UserBuyTicketInfo.Order> convertToOrderList(final Map<String, List<
133183
134184 // 한 오더내에서 모든 티켓이 USABLE 상태일 때만 취소 가능함
135185 final boolean canCancel = ticketInfos .stream ()
136- .allMatch (info -> info .ticketStatus () == UserBuyTicketInfo .TicketStatusForUi .USABLE );
186+ .allMatch (info -> info .ticketStatus () == UserBuyTicketInfoResponse .TicketStatusForUi .USABLE );
137187
138188 final BigDecimal refundAmount = refundAmountByOrderId .get (orderId );
139189 final String formattedRefund = refundAmount != null ? PriceFormatterUtil .formatPrice (refundAmount ) : null ;
140190
141- return new UserBuyTicketInfo .Order (orderDate , orderId , eventName , eventVenue , formattedRefund ,canCancel , ticketInfos );
191+ return new UserBuyTicketInfoResponse .Order (orderDate , orderId , eventName , eventVenue , formattedRefund ,canCancel , ticketInfos );
142192 })
143- .sorted (Comparator .comparing (UserBuyTicketInfo .Order ::orderDate ).reversed ())
193+ .sorted (Comparator .comparing (UserBuyTicketInfoResponse .Order ::orderDate ).reversed ())
144194 .toList ();
145195 }
146196
147197 private boolean isTicketDateExpired (final LocalDateTime endDate ) {
148198 return LocalDateTime .now ().isAfter (endDate );
149199 }
150200
151- private UserBuyTicketInfo .TicketStatusForUi toUiStatus (final TicketStatus status , final boolean expired ) {
201+ private UserBuyTicketInfoResponse .TicketStatusForUi toUiStatus (final TicketStatus status , final boolean expired ) {
152202 if (expired && status == TicketStatus .RESERVED ) {
153- return UserBuyTicketInfo .TicketStatusForUi .EXPIRED ;
203+ return UserBuyTicketInfoResponse .TicketStatusForUi .EXPIRED ;
154204 }
155205
156206 return switch (status ) {
157- case RESERVED -> UserBuyTicketInfo .TicketStatusForUi .USABLE ;
158- case USED -> UserBuyTicketInfo .TicketStatusForUi .USED ;
159- case CANCELED -> UserBuyTicketInfo .TicketStatusForUi .REFUNDED ;
207+ case RESERVED -> UserBuyTicketInfoResponse .TicketStatusForUi .USABLE ;
208+ case USED -> UserBuyTicketInfoResponse .TicketStatusForUi .USED ;
209+ case CANCELED -> UserBuyTicketInfoResponse .TicketStatusForUi .REFUNDED ;
160210 };
161211 }
162212
0 commit comments