Skip to content

Commit 7659691

Browse files
authored
merge: 결제 성공 로그 포맷 변경 및 환불 기한 추가 - PERMIT-SEOUL#241
fix: 결제 성공 로그 포맷 변경 및 환불 기한 추가 - PERMIT-SEOUL#241
2 parents eb3085b + a5448f1 commit 7659691

File tree

3 files changed

+47
-51
lines changed

3 files changed

+47
-51
lines changed

src/main/java/com/permitseoul/permitserver/domain/payment/api/service/PaymentService.java

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,14 @@
5858
import org.springframework.stereotype.Service;
5959

6060
import java.math.BigDecimal;
61+
import java.time.LocalDate;
6162
import java.time.LocalDateTime;
63+
import java.time.ZoneId;
64+
import java.time.temporal.ChronoUnit;
6265
import java.util.Base64;
6366
import java.util.List;
6467

68+
import static com.permitseoul.permitserver.global.util.LogFormUtil.maskPaymentKey;
6569
import static net.logstash.logback.argument.StructuredArguments.keyValue;
6670

6771
@Slf4j
@@ -130,14 +134,11 @@ public PaymentConfirmResponse getPaymentConfirm(final long userId,
130134

131135
final TossPaymentResponse tossPaymentResponse = getTossPaymentConfirm(authorizationHeader, paymentKey, reservation.getOrderId(), reservation.getTotalAmount());
132136

133-
log.info("토스 결제 승인 완료",
134-
(Object[]) LogFormUtil.paymentLog(
135-
userId,
136-
tossPaymentResponse.orderId(),
137-
tossPaymentResponse.paymentKey(),
138-
reservation.getReservationId(),
139-
tossPaymentResponse.totalAmount()
140-
)
137+
log.info("[Payment] 토스 결제 승인 완료 - orderId={}, paymentKey={}, reservationId={}, amount={}",
138+
tossPaymentResponse.orderId(),
139+
LogFormUtil.maskPaymentKey(tossPaymentResponse.paymentKey()),
140+
reservation.getReservationId(),
141+
tossPaymentResponse.totalAmount()
141142
);
142143

143144
updateReservationStatusAndTossPaymentResponseTime(reservation.getReservationId(), ReservationStatus.PAYMENT_SUCCESS);
@@ -202,23 +203,25 @@ public PaymentConfirmResponse getPaymentConfirm(final long userId,
202203
deleteReservationSessionByOrderId(orderId);
203204
throw handleFeignException(e, orderId, userId);
204205

205-
} catch (AlgorithmException e) { //todo: 결제는 됐는데, 티켓 발급 과정에서 실패했으므로, 따로 알림 구축해놔야될듯
206-
logPaymentSuccessButTicketIssueFailed(userId, reservationSessionKey, orderId, totalAmount, paymentKey, reservation.getReservationId());
206+
} catch (AlgorithmException e) {
207+
logPaymentSuccessButTicketIssueFailed(orderId, totalAmount, paymentKey, reservation.getReservationId());
207208
throw new TicketAlgorithmException(ErrorCode.INTERNAL_TICKET_ALGORITHM_ERROR);
208209

209-
} catch (IllegalEnumTransitionException e) { //todo: 결제는 됐는데, 티켓 발급 과정에서 실패했으므로, 따로 알림 구축해놔야될듯
210-
logPaymentSuccessButTicketIssueFailed(userId, reservationSessionKey, orderId, totalAmount, paymentKey, reservation.getReservationId());
210+
} catch (IllegalEnumTransitionException e) {
211+
logPaymentSuccessButTicketIssueFailed(orderId, totalAmount, paymentKey, reservation.getReservationId());
211212
throw new ReservationIllegalException(ErrorCode.INTERNAL_TRANSITION_ENUM_ERROR);
212213

213-
} catch (ReservationSessionNotFoundAfterPaymentSuccessException e) { //결제는 됐는데, 티켓 발급 과정에서 실패했으므로, 따로 알림 구축해놔야될듯
214-
logPaymentSuccessButTicketIssueFailed(userId, reservationSessionKey, orderId, totalAmount, paymentKey, reservation.getReservationId());
214+
} catch (ReservationSessionNotFoundAfterPaymentSuccessException e) {
215+
logPaymentSuccessButTicketIssueFailed(orderId, totalAmount, paymentKey, reservation.getReservationId());
215216
throw new NotFoundPaymentException(ErrorCode.NOT_FOUND_RESERVATION_SESSION_AFTER_PAYMENT_SUCCESS);
216217
}
217218
}
218219

219220
public void cancelPayment(final long userId, final String orderId) {
220221
try {
221222
final Payment payment = paymentRetriever.findPaymentByOrderId(orderId);
223+
validateCancelAvailablePeriod(payment.getEventId());
224+
222225
final List<Ticket> ticketList = ticketRetriever.findAllTicketsByOrderIdAndUserId(payment.getOrderId(), userId);
223226
validateTicketStatusForCancel(ticketList);
224227

@@ -245,6 +248,8 @@ public void cancelPayment(final long userId, final String orderId) {
245248

246249
} catch (PaymentNotFoundException e) {
247250
throw new NotFoundPaymentException(ErrorCode.NOT_FOUND_PAYMENT);
251+
} catch (EventNotfoundException e) {
252+
throw new NotFoundPaymentException(ErrorCode.NOT_FOUND_EVENT);
248253
} catch(FeignException e) {
249254
throw handleFeignException(e, orderId, userId);
250255
} catch (TicketNotFoundException e) {
@@ -263,6 +268,23 @@ public void cancelPayment(final long userId, final String orderId) {
263268
}
264269
}
265270

271+
private void validateCancelAvailablePeriod(final long eventId) {
272+
final Event event = eventRetriever.findEventById(eventId);
273+
274+
final LocalDate eventDate = event.getStartAt().toLocalDate();
275+
final LocalDate today = LocalDate.now(ZoneId.of("Asia/Seoul"));
276+
277+
// 오늘과 행사일 사이의 일수 계산
278+
long daysUntilEvent = ChronoUnit.DAYS.between(today, eventDate);
279+
280+
// 3일 전까지만 환불 가능
281+
if (daysUntilEvent < 3) {
282+
log.warn("[Payment Cancel] 취소 기한 초과 - eventId={}, eventDate={}, today={}, daysUntilEvent={}",
283+
eventId, eventDate, today, daysUntilEvent);
284+
throw new PaymentBadRequestException(ErrorCode.BAD_REQUEST_CANCEL_PERIOD_EXPIRED);
285+
}
286+
}
287+
266288
private void deleteReservationSessionByOrderId(final String orderId) {
267289
try {
268290
reservationSessionRemover.deleteByOrderId(orderId);
@@ -302,18 +324,15 @@ private void handleFailedTossPayment(final Reservation reservation,
302324
}
303325
}
304326

305-
private void logPaymentSuccessButTicketIssueFailed( final long userId,
306-
final String sessionKey,
307-
final String orderId,
308-
final BigDecimal totalAmount,
309-
final String paymentKey,
310-
final long reservationId) {
311-
log.error("토스 결제 승인 완료 -> 티켓 발급 실패",
312-
keyValue(Constants.USER_ID, userId),
313-
keyValue(Constants.ORDER_ID, orderId),
314-
keyValue(Constants.PAYMENT_KEY, LogFormUtil.maskPaymentKey(paymentKey)),
315-
keyValue(Constants.RESERVATION_ID, reservationId),
316-
keyValue(Constants.TOTAL_AMOUNT, totalAmount)
327+
private void logPaymentSuccessButTicketIssueFailed(final String orderId,
328+
final BigDecimal totalAmount,
329+
final String paymentKey,
330+
final long reservationId) {
331+
log.error("[Payment] 토스 결제 승인 완료 -> 티켓 발급 실패 - orderId={}, paymentKey={}, reservationId={}, amount={}",
332+
orderId,
333+
LogFormUtil.maskPaymentKey(paymentKey),
334+
reservationId,
335+
totalAmount
317336
);
318337
}
319338

@@ -341,7 +360,7 @@ private void logRollbackFailed(final long userId,
341360
final BigDecimal totalAmount,
342361
final String paymentKey) {
343362
log.error("[결제 승인 API - redis Rollback Failed] userId: {}, sessionKey: {}, orderId: {}, totalAmount: {}, paymentKey: {}",
344-
userId, sessionKey, orderId, totalAmount, LogFormUtil.maskPaymentKey(paymentKey));
363+
userId, sessionKey, orderId, totalAmount, maskPaymentKey(paymentKey));
345364
}
346365

347366
private void updateReservationStatusAndTossPaymentResponseTime(final long reservationId, final ReservationStatus status) {

src/main/java/com/permitseoul/permitserver/global/response/code/ErrorCode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public enum ErrorCode implements ApiCode {
3030
BAD_REQUEST_MISMATCH_TICKET_TYPE_ROUND(HttpStatus.BAD_REQUEST, 40016, "ticketType의 roundId와 다른 ticketRoundId 입니다."),
3131
BAD_REQUEST_MISMATCH_LIST_SIZE(HttpStatus.BAD_REQUEST, 40017, "list의 길이가 다릅니다."),
3232
BAD_REQUEST_REDIS_TICKET_TYPE_MISMATCH(HttpStatus.BAD_REQUEST, 40018, "redis ticket tpye mismatch 에러입니다. "),
33+
BAD_REQUEST_CANCEL_PERIOD_EXPIRED(HttpStatus.BAD_REQUEST, 40019, "환불 가능 기간이 아닙니다. 환불은 행사 시작일 기준 3일전까지만 가능합니다.(환불 정책 참고)."),
3334

3435

3536

src/main/java/com/permitseoul/permitserver/global/util/LogFormUtil.java

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
package com.permitseoul.permitserver.global.util;
22

3-
import com.permitseoul.permitserver.global.Constants;
4-
import lombok.AccessLevel;
5-
import lombok.NoArgsConstructor;
63
import lombok.experimental.UtilityClass;
7-
import net.logstash.logback.argument.StructuredArgument;
8-
9-
import java.math.BigDecimal;
10-
11-
import static net.logstash.logback.argument.StructuredArguments.keyValue;
124

135
@UtilityClass
146
public final class LogFormUtil {
@@ -22,22 +14,6 @@ public final class LogFormUtil {
2214
private static final int PAYMENT_KEY_LONG_PREFIX = 4;
2315
private static final int PAYMENT_KEY_LONG_SUFFIX = 5;
2416

25-
public static StructuredArgument[] paymentLog(
26-
final long userId,
27-
final String orderId,
28-
final String paymentKey,
29-
final long reservationId,
30-
final BigDecimal totalAmount
31-
) {
32-
return new StructuredArgument[] {
33-
keyValue(Constants.USER_ID, userId),
34-
keyValue(Constants.ORDER_ID, orderId),
35-
keyValue(Constants.PAYMENT_KEY, maskPaymentKey(paymentKey)),
36-
keyValue(Constants.RESERVATION_ID, reservationId),
37-
keyValue(Constants.TOTAL_AMOUNT, totalAmount)
38-
};
39-
}
40-
4117
public static String maskPaymentKey(final String paymentKey) {
4218
if (paymentKey == null || paymentKey.isBlank()) {
4319
return paymentKey;

0 commit comments

Comments
 (0)