Skip to content

Commit

Permalink
feat: 결제 실패 시 결제 상태를 ABORTED 로 변경한다. (#442)
Browse files Browse the repository at this point in the history
* feat: 결제 실패 시 결제 상태를 변경한다.

* style: 개행을 추가한다.

* docs: README.md 에 이슈해결을 추가한다.
  • Loading branch information
pushedrumex authored Dec 22, 2023
1 parent 76ae039 commit cf33e79
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 3 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,5 @@ https://dev.anifriends.site/docs/index.html
- [로그 세팅하기 1편. AOP, 로그백](https://prgrms.notion.site/1-AOP-a66142c842224edaacecfd338e6c95e5)
- [로그 세팅하기 2편. Promtail, Loki, Grafana](https://prgrms.notion.site/2-194c6b711e574d1c8dad2a3593b344fc)
- [존재하지 않은 객체와 협력하기](https://prgrms.notion.site/90ea0c42ffe04015be311bf2d2e5161b)
- [로그 파일이 커질 때 어떻게 하지?](https://prgrms.notion.site/215c4c3543f7457eb16739de036bd3ad?pvs=4)
- [로그 파일이 커질 때 어떻게 하지?](https://prgrms.notion.site/215c4c3543f7457eb16739de036bd3ad?pvs=4)
- [프로젝션과 인덱스로 조회성능 개선하기](https://prgrms.notion.site/4da1039c438d4b8b91deb89d57746d09)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.clova.anifriends.domain.payment.Payment;
import com.clova.anifriends.domain.payment.dto.response.PaymentResponse;
import com.clova.anifriends.domain.payment.exception.PaymentBadRequestException;
import com.clova.anifriends.domain.payment.exception.PaymentFailException;
import com.clova.anifriends.domain.payment.repository.PaymentRepository;
import com.clova.anifriends.global.exception.ExternalApiException;
import java.text.MessageFormat;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -16,13 +18,18 @@ public class PaymentService {
private final PaymentRepository paymentRepository;
private final PaymentClient paymentClient;

@Transactional
@Transactional(noRollbackFor = {PaymentFailException.class, ExternalApiException.class})
public PaymentResponse paySuccess(String orderId, String paymentKey, Integer amount) {
Payment payment = getPayment(orderId);
validatePaymentStatus(payment);
validatePaymentAmount(payment, amount);

paymentClient.confirmPayment(orderId, paymentKey, amount);
try {
paymentClient.confirmPayment(orderId, paymentKey, amount);
} catch (PaymentFailException | ExternalApiException exception) {
payment.fail();
throw exception;
}

payment.updatePaymentKey(paymentKey);
payment.success();
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/com/clova/anifriends/base/BaseIntegrationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import com.clova.anifriends.domain.applicant.repository.ApplicantRepository;
import com.clova.anifriends.domain.chat.repository.ChatMessageRepository;
import com.clova.anifriends.domain.chat.repository.ChatRoomRepository;
import com.clova.anifriends.domain.donation.repository.DonationRepository;
import com.clova.anifriends.domain.payment.repository.PaymentRepository;
import com.clova.anifriends.domain.payment.service.PaymentClient;
import com.clova.anifriends.domain.recruitment.repository.RecruitmentRepository;
import com.clova.anifriends.domain.review.repository.ReviewRepository;
import com.clova.anifriends.domain.shelter.repository.ShelterRepository;
import com.clova.anifriends.domain.volunteer.repository.VolunteerRepository;
import com.clova.anifriends.global.config.RedisConfig;
import com.clova.anifriends.global.config.SecurityConfig;
import com.clova.anifriends.global.image.S3Service;
import com.clova.anifriends.global.infrastructure.ApiService;
import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -52,6 +56,18 @@ public abstract class BaseIntegrationTest extends TestContainerStarter {
@Autowired
protected AnimalRepository animalRepository;

@Autowired
protected DonationRepository donationRepository;

@Autowired
protected PaymentRepository paymentRepository;

@Autowired
protected PaymentClient paymentClient;

@MockBean
protected ApiService apiService;

@MockBean
protected S3Service s3Service;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.clova.anifriends.domain.payment.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchException;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import com.clova.anifriends.base.BaseIntegrationTest;
import com.clova.anifriends.domain.donation.Donation;
import com.clova.anifriends.domain.donation.support.fixture.DonationFixture;
import com.clova.anifriends.domain.payment.Payment;
import com.clova.anifriends.domain.payment.dto.response.TossPaymentApiResponse;
import com.clova.anifriends.domain.payment.exception.PaymentFailException;
import com.clova.anifriends.domain.payment.vo.PaymentStatus;
import com.clova.anifriends.domain.shelter.Shelter;
import com.clova.anifriends.domain.shelter.support.ShelterFixture;
import com.clova.anifriends.domain.volunteer.Volunteer;
import com.clova.anifriends.domain.volunteer.support.VolunteerFixture;
import com.clova.anifriends.global.exception.ExternalApiException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

class PaymentIntegrationTest extends BaseIntegrationTest {

@Autowired
private PaymentService paymentService;

@Nested
@DisplayName("paySuccess 실행 시")
class PaySuccessTest {

@Test
@DisplayName("성공: 결제 상태가 DONE 으로 변경")
void paySuccess() {
// given
Shelter shelter = ShelterFixture.shelter();
Volunteer volunteer = VolunteerFixture.volunteer();
Donation donation = DonationFixture.donation(shelter, volunteer);
String mockPaymentKey = "mockPaymentKey";
Payment payment = new Payment(donation);

shelterRepository.save(shelter);
volunteerRepository.save(volunteer);
paymentRepository.save(payment);

when(apiService.post(any(), any(), any())).thenReturn(
new TossPaymentApiResponse("DONE"));

// when
paymentService.paySuccess(payment.getOrderId(), mockPaymentKey, donation.getAmount());

// then
Payment updatedPayment = paymentRepository.findById(payment.getPaymentId()).get();
assertThat(updatedPayment.getStatus()).isEqualTo(PaymentStatus.DONE);
}

@Test
@DisplayName("예외(ExternalApiException): PG Api 예외 발생 시 Payment 상태 ABORTED 로 변경")
void exceptionWhenPGApiException() {
// given
Shelter shelter = ShelterFixture.shelter();
Volunteer volunteer = VolunteerFixture.volunteer();
Donation donation = DonationFixture.donation(shelter, volunteer);
String mockPaymentKey = "mockPaymentKey";
Payment payment = new Payment(donation);

shelterRepository.save(shelter);
volunteerRepository.save(volunteer);
paymentRepository.save(payment);

when(apiService.post(any(), any(), any())).thenThrow(
new ExternalApiException("errorMessage"));

// when
Exception exception = catchException(
() -> paymentService.paySuccess(payment.getOrderId(), mockPaymentKey,
donation.getAmount()));

// then
Payment updatedPayment = paymentRepository.findById(payment.getPaymentId()).get();
assertThat(updatedPayment.getStatus()).isEqualTo(PaymentStatus.ABORTED);
assertThat(exception).isInstanceOf(ExternalApiException.class);
}

@Test
@DisplayName("예외(PaymentFailException): 결제 실패 시 Payment 상태 ABORTED 로 변경")
void exceptionWhenPaymentFail() {
// given
Shelter shelter = ShelterFixture.shelter();
Volunteer volunteer = VolunteerFixture.volunteer();
Donation donation = DonationFixture.donation(shelter, volunteer);
String mockPaymentKey = "mockPaymentKey";
Payment payment = new Payment(donation);

shelterRepository.save(shelter);
volunteerRepository.save(volunteer);
paymentRepository.save(payment);

when(apiService.post(any(), any(), any())).thenReturn(
new TossPaymentApiResponse("FAIL"));

// when
Exception exception = catchException(
() -> paymentService.paySuccess(payment.getOrderId(), mockPaymentKey,
donation.getAmount()));

// then
Payment updatedPayment = paymentRepository.findById(payment.getPaymentId()).get();
assertThat(updatedPayment.getStatus()).isEqualTo(PaymentStatus.ABORTED);
assertThat(exception).isInstanceOf(PaymentFailException.class);
}
}

}

0 comments on commit cf33e79

Please sign in to comment.