Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import com.kt.properties.TossPaymentsProperties;
import com.kt.security.CustomUserDetails;
import com.kt.service.order.OrderService;
import com.kt.service.payment.PaymentFacade;
import com.kt.service.payment.PaymentService;

import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -53,6 +54,7 @@ public class PaymentController extends SwaggerAssistance {

private final PaymentService paymentService;
private final OrderService orderService;
private final PaymentFacade paymentFacade;
private final TossPaymentsProperties tossPaymentsProperties;
private final RestTemplate restTemplate = new RestTemplate();

Expand Down Expand Up @@ -121,7 +123,7 @@ public ResponseEntity<?> confirmPayment(@RequestBody PaymentTossConfirmRequest r

if (response.getStatusCode() == HttpStatus.OK) {
Map<String, Object> tossPayment = response.getBody();
Long paymentId = paymentService.create(tossPayment, currentUser.getId());
Long paymentId = paymentFacade.completePayment(tossPayment, currentUser.getId(), orderIdLong);

Map<String, Object> responseBody = new HashMap<>(tossPayment);
responseBody.put("paymentId", paymentId);
Expand All @@ -138,6 +140,8 @@ public ResponseEntity<?> confirmPayment(@RequestBody PaymentTossConfirmRequest r
.body(e.getResponseBodyAsString());
} catch (Exception e) {
e.printStackTrace();

//TODO order 생성 기록 rollback
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Map.of(
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/com/kt/domain/order/Order.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,9 @@ public void updateStatus(OrderStatus newStatus) {
this.deliveredAt = LocalDate.now();
}
}

public void addOrderProduct(OrderProduct orderProduct) {
orderProducts.add(orderProduct);
orderProduct.assignOrder(this);
}
}
5 changes: 4 additions & 1 deletion src/main/java/com/kt/domain/order/OrderStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ public enum OrderStatus {
RETURN_REQUESTED("반품 요청"),
RETURNED("반품 완료"),
REFUND_REQUESTED("환불 요청"),
REFUNDED("환불 완료");
REFUNDED("환불 완료"),

PENDING_PAYMENT("결제 대기"),
PAYMENT_FAILED("결제 실패");

private final String description;
}
10 changes: 10 additions & 0 deletions src/main/java/com/kt/domain/orderproduct/OrderProduct.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,14 @@ public OrderProduct(Long count, Long variantId, Product product, Order order) {
this.product = product;
this.order = order;
}

public OrderProduct(Long count, Long variantId, Product product) {
this.count = count;
this.variantId = variantId;
this.product = product;
}

public void assignOrder(Order order) {
this.order = order;
}
}
116 changes: 66 additions & 50 deletions src/main/java/com/kt/service/order/OrderService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@

import static com.kt.common.support.ObjectUtils.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
Expand All @@ -18,24 +16,19 @@
import com.kt.common.request.Paging;
import com.kt.common.support.Preconditions;
import com.kt.domain.discount.Discount;
import com.kt.domain.discount.policy.DiscountPolicy;
import com.kt.domain.discount.policy.DiscountPolicyFactory;
import com.kt.domain.membership.Membership;
import com.kt.domain.order.Order;
import com.kt.domain.order.OrderStatus;
import com.kt.domain.orderproduct.OrderProduct;
import com.kt.domain.product.ProductStatus;
import com.kt.domain.shoppingaddress.ShoppingAddress;
import com.kt.domain.user.User;
import com.kt.dto.discount.response.DiscountResult;
import com.kt.dto.order.OrderCreateRequest;
import com.kt.dto.order.OrderProductRequest;
import com.kt.dto.order.OrderStatusUpdateRequest;
import com.kt.dto.order.OrderUpdateRequest;
import com.kt.dto.order.response.OrderListResponse;
import com.kt.dto.order.response.OrderDetailResponse;
import com.kt.dto.order.response.OrderProductResponse;
import com.kt.repository.discount.DiscountRepository;
import com.kt.repository.discountmembership.DiscountMembershipRepository;
import com.kt.repository.order.OrderRepository;
import com.kt.repository.order.OrderRepositoryCustom;
import com.kt.repository.orderproduct.OrderProductRepository;
Expand All @@ -48,7 +41,6 @@
import lombok.RequiredArgsConstructor;

@Service
@Transactional
@RequiredArgsConstructor
public class OrderService {
private final UserRepository userRepository;
Expand All @@ -58,15 +50,37 @@ public class OrderService {
private final OrderProductRepository orderProductRepository;
private final VariantRepository variantRepository;
private final OrderRepositoryCustom orderRepositoryCustom;
private final DiscountMembershipRepository discountMembershipRepository;
private final DiscountCalcService discountCalcService;

@Transactional
public Long create(Long userId, OrderCreateRequest request) {
var user = userRepository.findByIdOrThrow(userId, ErrorCode.NOT_FOUND_USER);

// 1. 주소, 상품 유효성 검증
var address = validateAddress(userId, request.receiverAddressId());
var orderProducts = createOrderProducts(request.products());

// 2. 주문 생성
var newOrder = new Order(
request.receiverName(),
request.receiverPhone(),
address.getAddress(),
user
);

orderProducts.forEach(newOrder::addOrderProduct);

// 4. 저장
orderRepository.save(newOrder);
orderProductRepository.saveAll(orderProducts);
return newOrder.getId();
}

private ShoppingAddress validateAddress(Long userId, Long receiverAddressId) {
ShoppingAddress address;

if (request.receiverAddressId() != null) {
address = shoppingAddressRepository.findByIdOrThrow(request.receiverAddressId(),
if (receiverAddressId != null) {
address = shoppingAddressRepository.findByIdOrThrow(receiverAddressId,
ErrorCode.NOT_FOUND_SHOPPING_ADDRESS);

// 사용자 본인이 등록한 배송지인지 검증
Expand All @@ -76,51 +90,45 @@ public Long create(Long userId, OrderCreateRequest request) {
.orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_SHOPPING_ADDRESS));
}

// 1. 주문 생성
var newOrder = new Order(
request.receiverName(),
request.receiverPhone(),
address.getAddress(),
user
return address;
}

private List<OrderProduct> createOrderProducts(List<OrderProductRequest> products) {
return products.stream()
.map(this::validateAndCreateOrderProduct)
.toList();
}

private OrderProduct validateAndCreateOrderProduct(OrderProductRequest productRequest) {
var product = productRepository.findByIdOrThrow(productRequest.productId(), ErrorCode.NOT_FOUND_PRODUCT);

//상품 상태 검증
Preconditions.validate(product.getStatus().equals(ProductStatus.ACTIVATED), ErrorCode.CANNOT_PURCHASE_PRODUCT);
//상품 재고 검증
Preconditions.validate(product.getStock() >= productRequest.productCount(), ErrorCode.NOT_ENOUGH_STOCK);

//선택한 상품의 옵션이 맞는지 검증
var variant = variantRepository.findByIdAndDeletedFalseOrThrow(productRequest.productVariantId(), ErrorCode.NOT_FOUND_VARIANT);
Preconditions.validate(variant.getProduct().getId().equals(product.getId()), ErrorCode.INVALID_VARIANT);

return new OrderProduct(
productRequest.productCount(),
productRequest.productVariantId(),
product
);
}

List<OrderProduct> orderProducts = new ArrayList<>();

// 2. 전체 product 검증
request.products().forEach(product -> {
var targetProduct = productRepository.findByIdOrThrow(product.productId(), ErrorCode.NOT_FOUND_PRODUCT);

Preconditions.validate(targetProduct.getStatus().equals(ProductStatus.ACTIVATED),
ErrorCode.CANNOT_PURCHASE_PRODUCT);
Preconditions.validate(targetProduct.getStock() >= product.productCount(), ErrorCode.NOT_ENOUGH_STOCK);
//선택한 상품의 옵션이 맞는지 검증
var variant = variantRepository.findByIdAndDeletedFalseOrThrow(product.productVariantId(),
ErrorCode.NOT_FOUND_VARIANT);
Preconditions.validate(variant.getProduct().getId().equals(targetProduct.getId()),
ErrorCode.INVALID_VARIANT);

// OrderProduct 생성
var newOrderProduct = new OrderProduct(
product.productCount(),
product.productVariantId(),
targetProduct,
newOrder
);

orderProducts.add(newOrderProduct);
});
@Transactional
public void save(Long orderId){
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

// 3. stock 차감
orderProducts.forEach(newProduct -> {
// stock 차감
order.getOrderProducts().forEach(newProduct -> {
var product = newProduct.getProduct();
product.updateStock(product.getStock() - newProduct.getCount());
});

// 4. 저장
orderRepository.save(newOrder);
orderProductRepository.saveAll(orderProducts);

return newOrder.getId();
order.updateStatus(OrderStatus.PAID);
}

public Page<OrderListResponse> getOrderList(Long userId, Paging paging) {
Expand Down Expand Up @@ -159,6 +167,7 @@ public Page<OrderListResponse> getOrderList(Long userId, Paging paging) {
});
}

@Transactional
public void cancel(Long orderId, Long userId) {
// orderId 존재 여부 검증
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);
Expand Down Expand Up @@ -209,6 +218,7 @@ public OrderDetailResponse getOrderDetail(Long userId, Long orderId) {
return OrderDetailResponse.from(order, products);
}

@Transactional
public void update(OrderUpdateRequest request, Long orderId, Long userId) {
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

Expand All @@ -228,6 +238,7 @@ public void update(OrderUpdateRequest request, Long orderId, Long userId) {
);
}

@Transactional
public void cancelByAdmin(Long orderId) {
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

Expand All @@ -238,6 +249,7 @@ public void cancelByAdmin(Long orderId) {
order.cancel();
}

@Transactional
public void requestRefund(Long orderId, Long userId) {
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

Expand All @@ -249,6 +261,7 @@ public void requestRefund(Long orderId, Long userId) {
order.requestRefund();
}

@Transactional
public void requestReturn(Long orderId, Long userId) {
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

Expand All @@ -259,6 +272,7 @@ public void requestReturn(Long orderId, Long userId) {
order.requestReturn();
}

@Transactional
public void approveRefund(Long orderId) {
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

Expand All @@ -267,6 +281,7 @@ public void approveRefund(Long orderId) {
order.approveRefund();
}

@Transactional
public void approveReturn(Long orderId) {
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

Expand All @@ -275,6 +290,7 @@ public void approveReturn(Long orderId) {
order.approveReturn();
}

@Transactional
public void updateStatus(OrderStatusUpdateRequest request, Long orderId) {
var order = orderRepository.findByIdOrThrow(orderId, ErrorCode.NOT_FOUND_ORDER);

Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/kt/service/payment/PaymentFacade.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.kt.service.payment;

import java.util.Map;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.kt.service.order.OrderService;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class PaymentFacade {
private final OrderService orderService;
private final PaymentService paymentService;

@Transactional
public Long completePayment(Map<String, Object> tossResponse, Long userId, Long orderId) {
var paymentId = paymentService.create(tossResponse, userId);
orderService.save(orderId);

return paymentId;
}
}
11 changes: 1 addition & 10 deletions src/main/java/com/kt/service/payment/PaymentService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,26 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.kt.common.exception.CustomException;
import com.kt.common.exception.ErrorCode;
import com.kt.common.support.Preconditions;
import com.kt.domain.discount.Discount;
import com.kt.domain.discount.policy.DiscountPolicy;
import com.kt.domain.discount.policy.DiscountPolicyFactory;
import com.kt.domain.order.Order;
import com.kt.domain.order.OrderStatus;
import com.kt.domain.orderproduct.OrderProduct;
import com.kt.domain.payment.Payment;
import com.kt.dto.discount.response.DiscountInfo;
import com.kt.dto.discount.response.DiscountResult;
import com.kt.dto.order.response.OrderProductResponse;
import com.kt.dto.payment.PaymentCreateRequest;
import com.kt.dto.payment.PaymentDetailResponse;
import com.kt.dto.payment.PaymentListResponse;
import com.kt.dto.payment.PaymentOrderInfoResponse;
import com.kt.dto.payment.PaymentTossCancelRequest;
import com.kt.dto.payment.PaymentTossCancelResponse;
import com.kt.dto.payment.PaymentTossConfirmRequest;
import com.kt.repository.order.OrderRepository;
import com.kt.repository.order.OrderRepositoryCustom;
import com.kt.repository.orderproduct.OrderProductRepositoryCustom;
Expand All @@ -40,6 +32,7 @@
import com.kt.repository.paymenttype.PaymentTypeRepository;
import com.kt.repository.user.UserRepository;
import com.kt.service.discount.DiscountCalcService;
import com.kt.service.order.OrderService;

import lombok.RequiredArgsConstructor;

Expand Down Expand Up @@ -78,8 +71,6 @@ public Long create(Map<String, Object> tossResponse, Long userId) {

Payment savedPayment = paymentRepository.save(payment);

order.updateStatus(OrderStatus.PAID);

return savedPayment.getId();
}

Expand Down
3 changes: 0 additions & 3 deletions src/test/java/com/kt/service/payment/PaymentServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,6 @@ void setUp() {
assertThat(payment.getTotalPrice()).isEqualTo(23000);
assertThat(payment.getDeliveryFee()).isEqualTo(3000);
assertThat(payment.getFinalPrice()).isEqualTo(20000);

Order updatedOrder = orderRepository.findById(order.getId()).get();
assertThat(updatedOrder.getOrderStatus()).isEqualTo(OrderStatus.PAID);
}

@Test
Expand Down
Loading