diff --git a/build.gradle b/build.gradle index ab9ad451..da34dc16 100644 --- a/build.gradle +++ b/build.gradle @@ -106,6 +106,8 @@ asciidoctor.doFirst { } asciidoctor { + baseDirFollowsSourceFile() // include 기준을 index.adoc 위치로 고정 + sources { include 'index.adoc' } // index.adoc을 진입점으로 attributes('snippets': snippetsDir.get().asFile) configurations 'asciidoctorExt' dependsOn test diff --git a/src/docs/asciidoc/_auth.adoc b/src/docs/asciidoc/_auth.adoc index 77d00074..c2f0e988 100644 --- a/src/docs/asciidoc/_auth.adoc +++ b/src/docs/asciidoc/_auth.adoc @@ -5,7 +5,6 @@ 요청 본문: include::{snippets}/member-login/request-fields.adoc[] - 응답 본문: include::{snippets}/member-login/response-fields.adoc[] diff --git a/src/docs/asciidoc/_payment.adoc b/src/docs/asciidoc/_payment.adoc new file mode 100644 index 00000000..b1f8adc8 --- /dev/null +++ b/src/docs/asciidoc/_payment.adoc @@ -0,0 +1,11 @@ +== 결제 API + +=== 1. 결제 요청 +`POST /payment` + +요청 본문: +include::{snippets}/payment-create/request-fields.adoc[] +응답 본문: +include::{snippets}/payment-create/response-fields.adoc[] +응답: +include::{snippets}/payment-create/http-response.adoc[] \ No newline at end of file diff --git a/src/docs/asciidoc/index.adoc b/src/docs/asciidoc/index.adoc index 89e5228c..48b2a0e0 100644 --- a/src/docs/asciidoc/index.adoc +++ b/src/docs/asciidoc/index.adoc @@ -14,6 +14,7 @@ include::_delivery_address.adoc[] include::_discount.adoc[] include::_coupon.adoc[] include::_deliverypolicy.adoc[] +include::_payment.adoc[] include::_customer_order.adoc[] include::_owner_order.adoc[] diff --git a/src/main/java/com/irum/come2us/domain/order/application/service/CustomerOrderService.java b/src/main/java/com/irum/come2us/domain/order/application/service/CustomerOrderService.java index 3ed39772..1c4c731a 100644 --- a/src/main/java/com/irum/come2us/domain/order/application/service/CustomerOrderService.java +++ b/src/main/java/com/irum/come2us/domain/order/application/service/CustomerOrderService.java @@ -270,8 +270,8 @@ public CustomerOrderResponse prepareOrder(CustomerOrderRequest request) { // 쿠폰 미리 차감 appliedCouponService.createAppliedCouponList(payment, request.couponIdList()); - // 주문 엔티티 생성 PENDING 상태 - String orderNum = "ORD-" + (int) ((Math.random() * 10000000)); + // 주문 엔티티 생성 PENDING 상태 8 자리 랜덤값 + String orderNum = "ORD-" + (int) ((Math.random() * 100000000)); Order order = Order.builder() diff --git a/src/test/java/com/irum/come2us/domain/payment/PaymentControllerTest.java b/src/test/java/com/irum/come2us/domain/payment/PaymentControllerTest.java new file mode 100644 index 00000000..28c31aa8 --- /dev/null +++ b/src/test/java/com/irum/come2us/domain/payment/PaymentControllerTest.java @@ -0,0 +1,82 @@ +package com.irum.come2us.domain.payment; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.irum.come2us.domain.payment.application.service.PaymentService; +import com.irum.come2us.domain.payment.presentation.controller.PaymentController; +import com.irum.come2us.domain.payment.presentation.dto.request.PaymentRequest; +import com.irum.come2us.domain.payment.presentation.dto.response.PaymentResponse; +import com.irum.come2us.global.config.SecurityTestConfig; +import com.irum.come2us.global.config.TestConfig; +import java.util.UUID; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +@WebMvcTest(controllers = PaymentController.class) +@AutoConfigureRestDocs +@Import({SecurityTestConfig.class, TestConfig.class}) +public class PaymentControllerTest { + + @Autowired private MockMvc mockMvc; + @MockitoBean private PaymentService paymentService; + @Autowired private ObjectMapper objectMapper; + + @Test + @DisplayName("결제 등록 API") + void paymentCreateApiTest() throws Exception { + UUID orderId = UUID.randomUUID(); + String orderNum = "ORD-777777"; + int totalAmount = 10000; + PaymentRequest request = new PaymentRequest("tossOrderId", "tosspaymentkey", orderId); + PaymentResponse response = new PaymentResponse(orderNum, totalAmount); + + Mockito.when(paymentService.createPayment(request)).thenReturn(response); + + mockMvc.perform( + post("/payment") + .with(csrf()) + .with(user("100").roles("CUSTOMER")) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.status").value(HttpStatus.OK.value())) + .andExpect(jsonPath("$.data.orderNum").value(orderNum)) + .andExpect(jsonPath("$.data.totalAmount").value(totalAmount)) + .andDo( + document( + "payment-create", + requestFields( + fieldWithPath("tossOrderId") + .description("토스에서 발급해주는 orderId"), + fieldWithPath("tossPaymentKey") + .description("토스에서 발급해주는 paymentKey"), + fieldWithPath("orderId").description("결제하려는 주문 id")), + responseFields( + fieldWithPath("success").description("성공 여부"), + fieldWithPath("status").description("HTTP 상태 코드"), + fieldWithPath("timestamp") + .description("응답 생성 시각 (ISO-8601)"), + subsectionWithPath("data").description("응답 데이터 객체")), + responseFields( + beneathPath("data").withSubsectionId("data"), + fieldWithPath("orderNum").description("주문 번호"), + fieldWithPath("totalAmount").description("실 결제 금액")))); + } +}