Skip to content

Commit

Permalink
Merge branch 'dev' into data
Browse files Browse the repository at this point in the history
  • Loading branch information
impati committed Aug 29, 2023
2 parents 0f8be7e + 797bfaf commit 595acee
Show file tree
Hide file tree
Showing 54 changed files with 838 additions and 488 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

// cache
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine'

// querydsl
implementation "com.querydsl:querydsl-jpa"
implementation "com.querydsl:querydsl-core"
Expand Down
11 changes: 11 additions & 0 deletions src/docs/asciidoc/apis.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,17 @@ include::{snippets}/product/findAll/request-fields.adoc[]
include::{snippets}/product/findAll/http-response.adoc[]
include::{snippets}/product/findAll/response-fields.adoc[]

== 메인 페이지 조회

=== 요청

include::{snippets}/product/main/http-request.adoc[]

=== 응답

include::{snippets}/product/main/http-response.adoc[]
include::{snippets}/product/main/response-fields.adoc[]

== 상품 상태 변경

=== 요청
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Objects;

import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
Expand Down Expand Up @@ -30,8 +31,10 @@ public class CartItem extends BaseEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "member_id")
private Long memberId;

@Column(name = "product_id")
private Long productId;

@Convert(converter = QuantityConverter.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.domain.AbstractAggregateRoot;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import lombok.Getter;

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
public abstract class BaseEntity extends AbstractAggregateRoot<BaseEntity> {
public abstract class BaseEntity {

@CreatedDate
private LocalDateTime createdAt;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
package com.woowa.woowakit.domain.order.api;

import com.woowa.woowakit.domain.auth.annotation.Authenticated;
import com.woowa.woowakit.domain.auth.annotation.User;
import com.woowa.woowakit.domain.auth.domain.AuthPrincipal;
import com.woowa.woowakit.domain.order.application.OrderService;
import com.woowa.woowakit.domain.order.dto.request.OrderCreateRequest;
import com.woowa.woowakit.domain.order.dto.request.PreOrderCreateCartItemRequest;
import com.woowa.woowakit.domain.order.dto.request.PreOrderCreateRequest;
import com.woowa.woowakit.domain.order.dto.response.OrderDetailResponse;
import com.woowa.woowakit.domain.order.dto.response.PreOrderResponse;
import java.util.List;

import javax.validation.Valid;
import lombok.RequiredArgsConstructor;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -21,6 +13,18 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.woowa.woowakit.domain.auth.annotation.Authenticated;
import com.woowa.woowakit.domain.auth.annotation.User;
import com.woowa.woowakit.domain.auth.domain.AuthPrincipal;
import com.woowa.woowakit.domain.order.application.OrderService;
import com.woowa.woowakit.domain.order.dto.request.OrderCreateRequest;
import com.woowa.woowakit.domain.order.dto.request.PreOrderCreateCartItemRequest;
import com.woowa.woowakit.domain.order.dto.request.PreOrderCreateRequest;
import com.woowa.woowakit.domain.order.dto.response.OrderDetailResponse;
import com.woowa.woowakit.domain.order.dto.response.PreOrderResponse;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/orders")
@RequiredArgsConstructor
Expand Down Expand Up @@ -54,7 +58,7 @@ public ResponseEntity<Long> createOrder(
@Authenticated final AuthPrincipal authPrincipal,
@Valid @RequestBody final OrderCreateRequest request
) {
Long orderId = orderService.order(authPrincipal, request);
Long orderId = orderService.pay(authPrincipal, request);
return ResponseEntity.status(HttpStatus.OK).body(orderId);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package com.woowa.woowakit.domain.order.application;

import java.util.List;

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

import com.woowa.woowakit.domain.auth.domain.AuthPrincipal;
import com.woowa.woowakit.domain.order.domain.Order;
import com.woowa.woowakit.domain.order.domain.OrderMapper;
import com.woowa.woowakit.domain.order.domain.OrderPayService;
import com.woowa.woowakit.domain.order.domain.OrderPlaceService;
import com.woowa.woowakit.domain.order.domain.OrderRepository;
import com.woowa.woowakit.domain.order.domain.mapper.OrderMapper;
import com.woowa.woowakit.domain.order.dto.request.OrderCreateRequest;
import com.woowa.woowakit.domain.order.dto.request.PreOrderCreateCartItemRequest;
import com.woowa.woowakit.domain.order.dto.request.PreOrderCreateRequest;
import com.woowa.woowakit.domain.order.dto.response.OrderDetailResponse;
import com.woowa.woowakit.domain.order.dto.response.PreOrderResponse;
import com.woowa.woowakit.domain.order.exception.OrderNotFoundException;

import io.micrometer.core.annotation.Counted;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
Expand All @@ -24,6 +29,8 @@ public class OrderService {

private final OrderRepository orderRepository;
private final OrderMapper orderMapper;
private final OrderPayService orderPayService;
private final OrderPlaceService orderPlaceService;

@Transactional(readOnly = true)
public OrderDetailResponse findOrderByOrderIdAndMemberId(
Expand Down Expand Up @@ -72,18 +79,9 @@ public PreOrderResponse preOrderCartItems(
return PreOrderResponse.from(orderRepository.save(order));
}

@Transactional
@Counted("order.order")
public Long order(final AuthPrincipal authPrincipal, final OrderCreateRequest request) {
log.info("주문 생성 memberId: {} orderId: {} paymentKey: {}", authPrincipal.getId(),
request.getOrderId(), request.getPaymentKey());
Order order = getOrderById(authPrincipal.getId(), request.getOrderId());
order.order(request.getPaymentKey());
return orderRepository.save(order).getId();
}

private Order getOrderById(final Long memberId, final Long orderId) {
return orderRepository.findByIdAndMemberId(orderId, memberId)
.orElseThrow(OrderNotFoundException::new);
public Long pay(final AuthPrincipal authPrincipal, final OrderCreateRequest request) {
orderPlaceService.place(authPrincipal, request.getOrderId());
orderPayService.pay(request.getOrderId(), request.getPaymentKey());
return request.getOrderId();
}
}
37 changes: 30 additions & 7 deletions src/main/java/com/woowa/woowakit/domain/order/domain/Order.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package com.woowa.woowakit.domain.order.domain;

import com.woowa.woowakit.domain.model.BaseEntity;
import com.woowa.woowakit.domain.model.Money;
import com.woowa.woowakit.domain.model.converter.MoneyConverter;
import com.woowa.woowakit.domain.order.domain.event.OrderCompleteEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Convert;
Expand All @@ -19,6 +17,11 @@
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import com.woowa.woowakit.domain.model.BaseEntity;
import com.woowa.woowakit.domain.model.Money;
import com.woowa.woowakit.domain.model.converter.MoneyConverter;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -38,11 +41,18 @@ public class Order extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Enumerated(EnumType.STRING)
@Column(name = "order_status")
private OrderStatus orderStatus;

@Convert(converter = MoneyConverter.class)
@Column(name = "total_price")
private Money totalPrice;

@Column(name = "member_id")
private Long memberId;

@Column(name = "uuid")
private String uuid;

Expand All @@ -68,8 +78,21 @@ private Money calculateTotalPrice(final List<OrderItem> orderItems) {
.reduce(Money.ZERO, Money::add);
}

public void order(final String paymentKey) {
registerEvent(new OrderCompleteEvent(this, paymentKey));
log.info("주문 완료 이벤트 발행 orderId: {}", id);
public void place() {
orderStatus = OrderStatus.PLACED;
}

public void cancel() {
orderStatus = OrderStatus.CANCELED;
}

public void pay() {
orderStatus = OrderStatus.PAYED;
}

public List<Long> collectProductIds() {
return orderItems.stream()
.map(OrderItem::getProductId)
.collect(Collectors.toUnmodifiableList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.woowa.woowakit.domain.order.domain;

import org.springframework.stereotype.Component;

import com.woowa.woowakit.domain.order.exception.InvalidPayRequestException;
import com.woowa.woowakit.domain.order.exception.OrderNotFoundException;
import com.woowa.woowakit.domain.order.exception.PayFailedException;

import io.micrometer.core.annotation.Counted;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.scheduler.Schedulers;

@Slf4j
@Component
@RequiredArgsConstructor
public class OrderPayService {

private final PaymentClient paymentClient;
private final OrderRepository orderRepository;
private final PayResultHandler payResultHandler;

@Counted("order.payment.request")
public void pay(final Long orderId, final String paymentKey) {
log.info("결제 요청 subscribe event: {}", paymentKey);

Order order = orderRepository.findById(orderId).orElseThrow(OrderNotFoundException::new);

paymentClient.validatePayment(paymentKey, order.getUuid(), order.getTotalPrice())
.publishOn(Schedulers.boundedElastic())
.doOnSuccess(ignore -> payResultHandler.save(orderId, paymentKey))
.doOnError(error -> payResultHandler.rollback(orderId, error))
.onErrorMap(IllegalArgumentException.class, InvalidPayRequestException::new)
.onErrorMap(IllegalStateException.class, PayFailedException::new)
.block();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.woowa.woowakit.domain.order.domain;

import java.util.List;

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

import com.woowa.woowakit.domain.auth.domain.AuthPrincipal;
import com.woowa.woowakit.domain.cart.domain.CartItemRepository;
import com.woowa.woowakit.domain.order.exception.OrderNotFoundException;
import com.woowa.woowakit.domain.product.domain.product.Product;
import com.woowa.woowakit.domain.product.domain.product.ProductRepository;

import io.micrometer.core.annotation.Counted;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Service
@RequiredArgsConstructor
@Slf4j
public class OrderPlaceService {

private final OrderRepository orderRepository;
private final CartItemRepository cartItemRepository;
private final ProductRepository productRepository;

@Transactional
@Counted("order.order")
public void place(final AuthPrincipal authPrincipal, final Long orderId) {
log.info("주문 수량 확보 및 장바구니 삭제 memberId: {} orderId: {}", authPrincipal.getId(), orderId);
Order order = getOrderById(authPrincipal.getId(), orderId);

order.place();
subtractProductQuantity(order);
deleteCartItems(order);
}

private void deleteCartItems(final Order order) {
List<Long> productIds = order.collectProductIds();
cartItemRepository.deleteAllByProductIdAndMemberId(order.getMemberId(), productIds);
log.info("장바구니 상품 삭제 memberId: {} productIds: {}", order.getMemberId(), productIds);
}

private void subtractProductQuantity(final Order order) {
List<Product> products = productRepository.findByIdsWithPessimistic(order.collectProductIds());
QuantityOfProducts quantityData = QuantityOfProducts.from(order);

for (Product product : products) {
log.info("상품 {}의 수량을 {}만큼 감소시킵니다. 현재 상품 수량: {}",
product.getId(), quantityData.getFrom(product), product.getQuantity().getValue());

product.subtractQuantity(quantityData.getFrom(product));

log.info("상품 {}의 수량이 {}로 변경되었습니다.", product.getId(), product.getQuantity().getValue());
}
}

private Order getOrderById(final Long memberId, final Long orderId) {
return orderRepository.findByIdAndMemberId(orderId, memberId)
.orElseThrow(OrderNotFoundException::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

@Getter
public enum OrderStatus {
ORDERED,
ORDERED, PLACED, CANCELED, PAYED,
}
Loading

0 comments on commit 595acee

Please sign in to comment.