-
Notifications
You must be signed in to change notification settings - Fork 4
[refactor] 정산 / 충전 관련 실패 로직 추가 #110
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
Changes from all commits
7d7fd85
890f3af
356439d
e20d8b2
cff6689
e2a2d6e
406423d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,16 @@ | ||
| package com.example.onlyone.domain.payment.repository; | ||
|
|
||
| import com.example.onlyone.domain.payment.entity.Payment; | ||
| import jakarta.persistence.LockModeType; | ||
| import jakarta.validation.constraints.NotBlank; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
| import org.springframework.data.jpa.repository.Lock; | ||
|
|
||
| import java.util.Optional; | ||
|
|
||
| public interface PaymentRepository extends JpaRepository<Payment, Long> { | ||
| Optional<Payment> findByTossOrderId(String tossOrderId); | ||
| @Lock(LockModeType.PESSIMISTIC_WRITE) | ||
| Optional<Payment> findByTossPaymentKey(String tossPaymentKey); | ||
|
|
||
| boolean existsByTossPaymentKey(String paymentKey); | ||
gkdudans marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -25,6 +25,7 @@ | |||||||||||||||||||||
| import lombok.extern.log4j.Log4j2; | ||||||||||||||||||||||
| import org.springframework.data.redis.core.RedisTemplate; | ||||||||||||||||||||||
| import org.springframework.stereotype.Service; | ||||||||||||||||||||||
| import org.springframework.transaction.annotation.Propagation; | ||||||||||||||||||||||
| import org.springframework.transaction.annotation.Transactional; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| import java.util.Optional; | ||||||||||||||||||||||
|
|
@@ -77,16 +78,25 @@ public void confirmPayment(@Valid SavePaymentRequestDto dto, HttpSession session | |||||||||||||||||||||
| // session.removeAttribute(dto.getOrderId()); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /* 토스페이먼츠 결제 승인 */ | ||||||||||||||||||||||
| @Transactional | ||||||||||||||||||||||
gkdudans marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||
| public ConfirmTossPayResponse confirm(ConfirmTossPayRequest req) { | ||||||||||||||||||||||
| // 멱등성 체크: 이미 처리된 주문인지 확인 | ||||||||||||||||||||||
| Optional<Payment> existingPayment = paymentRepository.findByTossOrderId(req.getOrderId()); | ||||||||||||||||||||||
| if (existingPayment.isPresent()) { | ||||||||||||||||||||||
| // 멱등성, 동시성 보호: paymentKey로 행 잠금 | ||||||||||||||||||||||
| Payment payment = paymentRepository.findByTossPaymentKey(req.getPaymentKey()) | ||||||||||||||||||||||
| .orElseGet(() -> { | ||||||||||||||||||||||
| Payment p = Payment.builder() | ||||||||||||||||||||||
| .tossOrderId(req.getOrderId()) | ||||||||||||||||||||||
| .tossOrderId(req.getOrderId()) | ||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 중복된 tossOrderId 설정
Payment p = Payment.builder()
.tossOrderId(req.getOrderId())
- .tossOrderId(req.getOrderId())
.status(Status.IN_PROGRESS)📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| .status(Status.IN_PROGRESS) | ||||||||||||||||||||||
| .totalAmount(req.getAmount()) | ||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||
| return paymentRepository.save(p); | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| if (payment.getStatus() == Status.DONE) { | ||||||||||||||||||||||
| throw new CustomException(ErrorCode.ALREADY_COMPLETED_PAYMENT); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| ConfirmTossPayResponse response; | ||||||||||||||||||||||
| // 토스페이먼츠 승인 API 호출 | ||||||||||||||||||||||
| final ConfirmTossPayResponse response; | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| // tossPaymentClient를 통해 호출 | ||||||||||||||||||||||
| response = tossPaymentClient.confirmPayment(req); | ||||||||||||||||||||||
| } catch (FeignException.BadRequest e) { | ||||||||||||||||||||||
| throw new CustomException(ErrorCode.INVALID_PAYMENT_INFO); | ||||||||||||||||||||||
|
|
@@ -95,13 +105,14 @@ public ConfirmTossPayResponse confirm(ConfirmTossPayRequest req) { | |||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||
| throw new CustomException(ErrorCode.INTERNAL_SERVER_ERROR); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| // 지갑/거래 업데이트 | ||||||||||||||||||||||
| User user = userService.getCurrentUser(); | ||||||||||||||||||||||
| Wallet wallet = walletRepository.findByUser(user) | ||||||||||||||||||||||
| .orElseThrow(() -> new CustomException(ErrorCode.WALLET_NOT_FOUND)); | ||||||||||||||||||||||
| int amount = Math.toIntExact(req.getAmount()); | ||||||||||||||||||||||
| // 포인트 업데이트 | ||||||||||||||||||||||
| int amount = Math.toIntExact(response.getTotalAmount()); | ||||||||||||||||||||||
| // 지갑 증액 | ||||||||||||||||||||||
| wallet.updateBalance(wallet.getBalance() + amount); | ||||||||||||||||||||||
| // 충전(결제) 기록 | ||||||||||||||||||||||
| // 거래 기록 | ||||||||||||||||||||||
| WalletTransaction walletTransaction = WalletTransaction.builder() | ||||||||||||||||||||||
| .type(Type.CHARGE) | ||||||||||||||||||||||
| .amount(amount) | ||||||||||||||||||||||
|
|
@@ -111,15 +122,47 @@ public ConfirmTossPayResponse confirm(ConfirmTossPayRequest req) { | |||||||||||||||||||||
| .targetWallet(wallet) | ||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||
| walletTransactionRepository.save(walletTransaction); | ||||||||||||||||||||||
| Payment payment = Payment.builder() | ||||||||||||||||||||||
| .tossPaymentKey(response.getPaymentKey()) | ||||||||||||||||||||||
| .tossOrderId(response.getOrderId()) | ||||||||||||||||||||||
| .totalAmount(response.getTotalAmount()) | ||||||||||||||||||||||
| .method(Method.from(response.getMethod())) | ||||||||||||||||||||||
| .status(Status.from(response.getStatus())) | ||||||||||||||||||||||
| .walletTransaction(walletTransaction) | ||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||
| payment.updateOnConfirm(response.getStatus(), response.getMethod()); | ||||||||||||||||||||||
| walletTransaction.updatePayment(payment); | ||||||||||||||||||||||
| return response; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @Transactional(propagation = Propagation.REQUIRES_NEW) | ||||||||||||||||||||||
| public void reportFail(ConfirmTossPayRequest req) { | ||||||||||||||||||||||
| // 멱등성, 동시성 보호: paymentKey로 행 잠금 | ||||||||||||||||||||||
| Payment payment = paymentRepository.findByTossPaymentKey(req.getPaymentKey()) | ||||||||||||||||||||||
| .orElseGet(() -> { | ||||||||||||||||||||||
| Payment p = Payment.builder() | ||||||||||||||||||||||
| .tossOrderId(req.getOrderId()) | ||||||||||||||||||||||
| .totalAmount(req.getAmount()) | ||||||||||||||||||||||
| .status(Status.IN_PROGRESS) | ||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||
| return paymentRepository.save(p); | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| // 이미 완료된 결제면 기록하지 않음 | ||||||||||||||||||||||
| if (payment.getStatus() == Status.DONE) { | ||||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| if (req.getPaymentKey() != null && | ||||||||||||||||||||||
| payment.getTossPaymentKey() != null && | ||||||||||||||||||||||
| payment.getTossPaymentKey().equals(req.getPaymentKey())) { | ||||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
Comment on lines
+146
to
+150
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 이상한 멱등성 체크 로직 이 멱등성 체크 로직이 부자연스럽습니다. 이미 - if (req.getPaymentKey() != null &&
- payment.getTossPaymentKey() != null &&
- payment.getTossPaymentKey().equals(req.getPaymentKey())) {
- return;
- }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| // 실패 기록 | ||||||||||||||||||||||
| User user = userService.getCurrentUser(); | ||||||||||||||||||||||
| Wallet wallet = walletRepository.findByUser(user) | ||||||||||||||||||||||
| .orElseThrow(() -> new CustomException(ErrorCode.WALLET_NOT_FOUND)); | ||||||||||||||||||||||
| WalletTransaction walletTransaction = WalletTransaction.builder() | ||||||||||||||||||||||
| .type(Type.CHARGE) | ||||||||||||||||||||||
| .amount(Math.toIntExact(req.getAmount())) | ||||||||||||||||||||||
| .balance(wallet.getBalance()) | ||||||||||||||||||||||
| .walletTransactionStatus(WalletTransactionStatus.FAILED) | ||||||||||||||||||||||
| .wallet(wallet) | ||||||||||||||||||||||
| .targetWallet(wallet) | ||||||||||||||||||||||
| .build(); | ||||||||||||||||||||||
| walletTransactionRepository.save(walletTransaction); | ||||||||||||||||||||||
| // Payment 갱신 | ||||||||||||||||||||||
| payment.updateStatus(Status.CANCELED); | ||||||||||||||||||||||
| walletTransaction.updatePayment(payment); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.