From 1e0dbf0dcaf5cefc29bee696fa24acbb793b7666 Mon Sep 17 00:00:00 2001 From: Chan Jin Date: Sun, 9 Jul 2023 14:31:16 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor=20:=20=EC=A0=95=EC=82=B0=EC=84=9C,?= =?UTF-8?q?=EC=A0=95=EC=82=B0=EC=84=9C=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=ED=8F=AC=EB=A7=B7=20=EC=88=98=EC=A0=95=20(#562)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : 정산서 메일 포맷 수정 * refactor : 정산서 포맷 수정 --- .../src/main/resources/templates/eventSettlement.html | 4 ++-- .../src/main/resources/templates/settlement.html | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/DuDoong-Infrastructure/src/main/resources/templates/eventSettlement.html b/DuDoong-Infrastructure/src/main/resources/templates/eventSettlement.html index e43270f0..f2a6ea00 100644 --- a/DuDoong-Infrastructure/src/main/resources/templates/eventSettlement.html +++ b/DuDoong-Infrastructure/src/main/resources/templates/eventSettlement.html @@ -41,10 +41,10 @@
- 입금과 세금 계산서 발행을 위해 + 입금을 위해
- 입금받으실 분의 주민등록번호와 성함을 평문으로, + 입금받으실 분의 성함을 평문으로,
통장사본은 첨부하셔서 support@dudoong.com 으로 이메일을 보내주시면 감사하겠습니다. diff --git a/DuDoong-Infrastructure/src/main/resources/templates/settlement.html b/DuDoong-Infrastructure/src/main/resources/templates/settlement.html index e100d618..e973b578 100644 --- a/DuDoong-Infrastructure/src/main/resources/templates/settlement.html +++ b/DuDoong-Infrastructure/src/main/resources/templates/settlement.html @@ -139,10 +139,10 @@
두둥의 매출인 수수료에 대해서는 매출 발생이 확정된 공연 종료일을 기준으로 매출이 발생한 것으로 봅니다.
-
- 이에 대한 증빙으로 두둥에서 호스트 앞으로 수수료에 대한 전자세금계산서를 발행해 드릴때 - 공연의 종료일을 기준으로 발급해드립니다. -
+ + + +
정산드린 금액에 대해선 입금 받는 호스트 분께서 성실하게 세금에대해 신고할 의무가 있습니다.
From 547855506b2c2a012f814b18f3d6add981ec6f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EA=B2=BD=EB=AF=BC?= Date: Sun, 9 Jul 2023 21:43:46 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat=20:=20=EC=A3=BC=EB=AC=B8=EC=B7=A8?= =?UTF-8?q?=EC=86=8C=20feign=20retryer=20bean=20=EC=B6=94=EA=B0=80=20(#564?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : 주문취소 retry 추가 * chore : 불필요 dependency 삭제 * feat : 500번대 retry 먼저 시도 --------- Co-authored-by: 이찬진 --- .../band/gosrock/common/annotation/Phone.java | 5 +- .../client/PaymentsCancelClient.java | 2 +- .../config/PaymentCancelErrorDecoder.java | 36 +++++++++++- .../client/PaymentsCancelClientTest.java | 56 +++++++++++++++++++ 4 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 DuDoong-Infrastructure/src/test/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClientTest.java diff --git a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java b/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java index 9939b034..bdabce60 100644 --- a/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java +++ b/DuDoong-Common/src/main/java/band/gosrock/common/annotation/Phone.java @@ -2,7 +2,10 @@ import band.gosrock.common.validator.PhoneValidator; -import java.lang.annotation.*; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import javax.validation.Constraint; @Target({ElementType.FIELD}) diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClient.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClient.java index 7de07d59..924c7104 100644 --- a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClient.java +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClient.java @@ -12,7 +12,7 @@ @FeignClient( name = "PaymentsCancelClient", - url = "https://api.tosspayments.com", + url = "${feign.toss.url}", configuration = {PaymentsCancelConfig.class}) public interface PaymentsCancelClient { @PostMapping("/v1/payments/{paymentKey}/cancel") diff --git a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/config/PaymentCancelErrorDecoder.java b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/config/PaymentCancelErrorDecoder.java index 90950629..7447884f 100644 --- a/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/config/PaymentCancelErrorDecoder.java +++ b/DuDoong-Infrastructure/src/main/java/band/gosrock/infrastructure/outer/api/tossPayments/config/PaymentCancelErrorDecoder.java @@ -6,17 +6,47 @@ import band.gosrock.infrastructure.outer.api.tossPayments.exception.PaymentsCancelErrorCode; import band.gosrock.infrastructure.outer.api.tossPayments.exception.PaymentsUnHandleException; import band.gosrock.infrastructure.outer.api.tossPayments.exception.TossPaymentsErrorDto; +import feign.FeignException; import feign.Response; +import feign.RetryableException; +import feign.Retryer; import feign.codec.ErrorDecoder; +import java.util.concurrent.TimeUnit; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; public class PaymentCancelErrorDecoder implements ErrorDecoder { + private static final long PERIOD = 500L; + private static final long MAX_PERIOD = TimeUnit.SECONDS.toMillis(3L); + private static final int MAX_ATTEMPTS = 3; + + @Bean + Retryer.Default retryer() { + return new Retryer.Default(PERIOD, MAX_PERIOD, MAX_ATTEMPTS); + } + @Override public Exception decode(String methodKey, Response response) { - TossPaymentsErrorDto body = TossPaymentsErrorDto.from(response); try { - PaymentsCancelErrorCode paymentsCancelErrorCode = + FeignException exception = feign.FeignException.errorStatus(methodKey, response); + int status = response.status(); + // 500번대는 기본적으로 리트라이 + if (HttpStatus.valueOf(status).is5xxServerError()) { + throw new RetryableException( + status, + exception.getMessage(), + response.request().httpMethod(), + exception, + null, + response.request()); + } + // payments 에러 코드 Decode + TossPaymentsErrorDto body = TossPaymentsErrorDto.from(response); + + final PaymentsCancelErrorCode paymentsCancelErrorCode = PaymentsCancelErrorCode.valueOf(body.getCode()); - ErrorReason errorReason = paymentsCancelErrorCode.getErrorReason(); + final ErrorReason errorReason = paymentsCancelErrorCode.getErrorReason(); + throw new DuDoongDynamicException( errorReason.getStatus(), errorReason.getCode(), errorReason.getReason()); } catch (IllegalArgumentException e) { diff --git a/DuDoong-Infrastructure/src/test/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClientTest.java b/DuDoong-Infrastructure/src/test/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClientTest.java new file mode 100644 index 00000000..efdfa1db --- /dev/null +++ b/DuDoong-Infrastructure/src/test/java/band/gosrock/infrastructure/outer/api/tossPayments/client/PaymentsCancelClientTest.java @@ -0,0 +1,56 @@ +package band.gosrock.infrastructure.outer.api.tossPayments.client; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.catchThrowable; + +import band.gosrock.infrastructure.InfraIntegrateProfileResolver; +import band.gosrock.infrastructure.InfraIntegrateTestConfig; +import band.gosrock.infrastructure.outer.api.tossPayments.dto.request.CancelPaymentsRequest; +import feign.RetryableException; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.spec.internal.HttpStatus; +import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; + +@ContextConfiguration +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = InfraIntegrateTestConfig.class) +@AutoConfigureWireMock(port = 0) +@ActiveProfiles(resolver = InfraIntegrateProfileResolver.class) +@TestPropertySource(properties = {"feign.toss.url=http://localhost:${wiremock.server.port}"}) +class PaymentsCancelClientTest { + private static final String IDEMPOTENCY_KEY = "idempotency-key"; + private static final String PAYMENT_KEY = "1234"; + private static final CancelPaymentsRequest REQUEST = + CancelPaymentsRequest.builder().cancelReason("test").build(); + @Autowired private PaymentsCancelClient paymentsCancelClient; + + @Test + public void 주문취소_실패시_멱등성_테스트() { + final String URL = "/v1/payments/" + PAYMENT_KEY + "/cancel"; + // given + stubFor( + post(urlEqualTo(URL)) + .willReturn(aResponse().withStatus(HttpStatus.SERVICE_UNAVAILABLE))); + + // when + Throwable exception = + catchThrowable( + () -> paymentsCancelClient.execute(IDEMPOTENCY_KEY, PAYMENT_KEY, REQUEST)); + + // then + assertThat(exception).isInstanceOf(RetryableException.class); + verify(3, postRequestedFor(urlEqualTo(URL))); + } +}