Skip to content

Commit

Permalink
[FIX] merge develop
Browse files Browse the repository at this point in the history
  • Loading branch information
YongNyeo committed Jan 18, 2024
2 parents 1e40364 + 445bf42 commit 382d4af
Show file tree
Hide file tree
Showing 36 changed files with 962 additions and 228 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/ci_gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ jobs:
run: echo "${{ secrets.APPLICATION_TEST }}" > ./src/test/resources/application.yml
shell: bash

## create test ddl.sql
- name: make test ddl.sql
run: |
touch ./src/test/resources/ddl.sql
shell: bash
- name: deliver test ddl.sql
run: echo "${{ secrets.DDL }}" > ./src/test/resources/ddl.sql
shell: bash
# ## create test ddl.sql
# - name: make test ddl.sql
# run: |
# touch ./src/test/resources/ddl.sql
# shell: bash
# - name: deliver test ddl.sql
# run: echo "${{ secrets.DDL }}" > ./src/test/resources/ddl.sql
# shell: bash


## Gradle Test를 실행한다
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public enum ErrorCode {
COUPON_ALREADY_USED(BAD_REQUEST, "이미 사용 완료한 쿠폰입니다."),
COUPON_NOT_AVAILABLE(BAD_REQUEST, "유효하지 않은 쿠폰입니다."),
COUPON_STOCK_INVALID(BAD_REQUEST,"쿠폰 수량은 0개 이상이어야 합니다."),
// TODO: DELIVERY_FEE_COUPON_ALREADY_APPLIED 통합 논의 필요
COUPON_ALREADY_APPLIED_PRODUCT(BAD_REQUEST,"이미 쿠폰이 적용된 상품입니다"),
COUPON_BENEFIT_VALUE_EXCEED(BAD_REQUEST,"쿠폰의 할인값은 최대할인값을 초과할 수 없습니다."),
COUPON_PRICE_NOT_ENOUGH(BAD_REQUEST,"쿠폰의 최수 주문 금액 미만입니다."),
Expand Down Expand Up @@ -68,6 +69,9 @@ public enum ErrorCode {
PRODUCT_NOT_AVAILABLE_ORDER(BAD_REQUEST, "주문할 수 없는 상품입니다."),
UPDATED_POINT_VALUE_INVALID(BAD_REQUEST, "갱신할 포인트의 값이 유효하지 않습니다."),
ORDERSHEET_ALREADY_ORDERED(BAD_REQUEST, "이미 주문이 완료된 주문서입니다."),
DELIVERY_FEE_COUPON_ALREADY_APPLIED(BAD_REQUEST, "이미 적용된 배송비 쿠폰입니다."),
// TODO: 적용 할 수 없는 쿠폰 에러 메시지 통합 논의 필요
DELIVERY_FEE_COUPON_NOT_APPLICABLE(BAD_REQUEST, "배송비가 없는 상품입니다."),
// 401
AUTH_MISSING_CREDENTIALS(UNAUTHORIZED, "사용자의 인증 정보를 찾을 수 없습니다."),
SECURITY_UNAUTHORIZED(UNAUTHORIZED, "인증 정보가 유효하지 않습니다"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@
import com.programmers.smrtstore.domain.coupon.infrastructure.CouponJpaRepository;
import com.programmers.smrtstore.domain.coupon.presentation.res.CouponResponse;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.req.SelectedCouponsRequest;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.vo.*;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.vo.ApplicableDeliveryFeeCoupons;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.vo.ApplicableProductCoupons;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.vo.CouponApplyResult;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.vo.OrderSheetCouponInfo;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.vo.SelectedCoupons;
import com.programmers.smrtstore.domain.orderManagement.orderSheet.presentation.dto.vo.SelectedCouponsWithCouponApplyResult;
import com.programmers.smrtstore.domain.orderManagement.orderedProduct.domain.entity.OrderedProduct;
import com.programmers.smrtstore.domain.product.domain.entity.Product;
import com.programmers.smrtstore.domain.product.exception.ProductException;
import com.programmers.smrtstore.domain.product.infrastructure.ProductJpaRepository;
import com.programmers.smrtstore.domain.user.domain.entity.User;
import com.programmers.smrtstore.domain.user.exception.UserException;
import com.programmers.smrtstore.domain.user.infrastructure.UserJpaRepository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@RequiredArgsConstructor
public class OrderCouponService {
Expand All @@ -43,45 +50,96 @@ public class OrderCouponService {
public OrderSheetCouponInfo getOrderSheetCouponInfoWithSelectedCoupons(Long userId, List<OrderedProduct> orderedProducts, SelectedCouponsRequest selectedCouponsRequest) {
ApplicableProductCoupons applicableProductCoupons = getApplicableProductCoupons(userId, orderedProducts);
ApplicableDeliveryFeeCoupons applicableDeliveryFeeCoupons = getApplicableDeliveryFeeCoupons();
List<CouponResponse> cartCoupons = getCartCoupons().stream().map(coupon -> CouponResponse.from(coupon)).toList();
List<CouponResponse> cartCoupons = getCartCoupons().stream().map(CouponResponse::from)
.toList();

// TODO: 함수 분리
// 쿠폰 entity 로 변환
Map<Long, Coupon> selectedProductCoupons = new HashMap<>();
for (OrderedProduct orderedProduct : orderedProducts) {
if (selectedCouponsRequest.getSelectedProductCouponListsByOrderedProductId().containsKey(orderedProduct.getId())) {
selectedProductCoupons.put(orderedProduct.getId(), getCouponJpaRepositoryById(selectedCouponsRequest.getSelectedProductCouponListsByOrderedProductId().get(orderedProduct.getId())));
}
}

Coupon cartCoupon = couponJpaRepository.findById(selectedCouponsRequest.getSelectedCartCoupons())
// 장바구니 쿠폰 가져오기
Coupon cartCoupon = couponJpaRepository.findById(selectedCouponsRequest.getSelectedCartCouponId())
.orElseThrow(()->new CouponException(ErrorCode.COUPON_NOT_FOUND));

SelectedCoupons selectedCoupons = getSelectedCoupons(selectedCouponsRequest);

// 할인 금액 적용 결과
Map<Long, List<CouponApplyResult>> discountsByOrderedProductId = OrderCouponDiscountCalculator.getCouponApplyResult(orderedProducts,selectedProductCoupons ,cartCoupon);

// response 로 보낼 쿠폰 정보
SelectedCoupons selectedCoupons = getSelectedCoupons(selectedCouponsRequest);
CouponResponse cartCouponResponses = CouponResponse.from(cartCoupon);

return new OrderSheetCouponInfo(discountsByOrderedProductId, selectedCoupons, applicableProductCoupons, applicableDeliveryFeeCoupons, cartCoupons);
}

//2. 쿠폰 선택X, 쿠폰 서비스에서 자체적으로 최적의 쿠폰 조합을 제공해야함. -> 여기선 selectedCoupons 을 최적 알고리즘으로 반환
public OrderSheetCouponInfo getOrderSheetCouponInfo(Long userId, List<OrderedProduct> orderedProducts) {


Map<Long, List<Coupon>> orderedProductCouponMap = new HashMap<>(); // OrderProductId에 적용 가능한 coupon List

// orderedProduct 의 Id 를 key 로 하여 쿠폰 Map 만듬
for (OrderedProduct orderedProduct : orderedProducts) {
List<Coupon> productCoupons = getProductCouponsByUserIdAndProductId(userId, orderedProduct.getProduct().getId());
List<Coupon> productCoupons = getProductCouponsByUserIdAndProductId(userId,
orderedProduct.getProduct().getId());
orderedProductCouponMap.put(orderedProduct.getId(), productCoupons);
}

// 장바구니 쿠폰 가져오기
List<Coupon> cartCoupons = getCartCoupons();
SelectedCouponsWithCouponApplyResult selectedCouponsWithCouponApplyResult = OrderCouponDiscountCalculator.getMaxDiscountCouponApplyResult(orderedProducts, orderedProductCouponMap, cartCoupons);
List<CouponResponse> cartCouponResponses = cartCoupons.stream().map(cartCoupon -> CouponResponse.from(cartCoupon)).toList();

ApplicableProductCoupons applicableProductCoupons = getApplicableProductCoupons(userId, orderedProducts);
ApplicableDeliveryFeeCoupons applicableDeliveryFeeCoupons = getApplicableDeliveryFeeCoupons();
// 최대 할인 쿠폰 적용 결과 + 적용한 쿠폰 가져오기
SelectedCouponsWithCouponApplyResult selectedCouponsWithCouponApplyResult =
OrderCouponDiscountCalculator.getMaxDiscountCouponApplyResult(orderedProducts,
orderedProductCouponMap, cartCoupons);
// 적용 되어진 쿠폰 리스트 가져오기
SelectedCoupons selectedCoupons = selectedCouponsWithCouponApplyResult.getSelectedCoupons();
Map<Long, List<CouponApplyResult>> discountsByOrderedProductId = selectedCouponsWithCouponApplyResult.getCouponApplyResult();
// 쿠폰 적용 결과 가져오기
Map<Long, List<CouponApplyResult>> discountsByOrderedProductId =
selectedCouponsWithCouponApplyResult.getCouponApplyResult();

// 장바구니 쿠폰 Response 로 변환
List<CouponResponse> cartCouponResponses = cartCoupons.stream().map(CouponResponse::from)
.toList();

// 적용 가능한 쿠폰들
ApplicableProductCoupons applicableProductCoupons = getApplicableProductCoupons(userId,
orderedProducts);

// 적용 가능한 배송비 쿠폰
ApplicableDeliveryFeeCoupons applicableDeliveryFeeCoupons = getApplicableDeliveryFeeCoupons();

return new OrderSheetCouponInfo(discountsByOrderedProductId, selectedCoupons,
applicableProductCoupons, applicableDeliveryFeeCoupons, cartCouponResponses);
}

public Map<Long, List<CouponApplyResult>> calCouponApplyResult(
List<OrderedProduct> orderedProducts, SelectedCouponsRequest selectedCouponsRequest
) {
// 쿠폰 entity 로 변환
Map<Long, Coupon> selectedProductCoupons = new HashMap<>();
for (OrderedProduct orderedProduct : orderedProducts) {
if (selectedCouponsRequest.getSelectedProductCouponListsByOrderedProductId()
.containsKey(orderedProduct.getId())) {
selectedProductCoupons.put(orderedProduct.getId(), getCouponJpaRepositoryById(
selectedCouponsRequest.getSelectedProductCouponListsByOrderedProductId()
.get(orderedProduct.getId())));
}
}

// 장바구니 쿠폰 가져오기
Coupon cartCoupon = couponJpaRepository.findById(
selectedCouponsRequest.getSelectedCartCouponId())
.orElseThrow(() -> new CouponException(ErrorCode.COUPON_NOT_FOUND));

// 최대 할인 쿠폰 적용 결과 + 적용한 쿠폰 가져오기
Map<Long, List<CouponApplyResult>> selectedCouponsWithCouponApplyResult =
OrderCouponDiscountCalculator.getCouponApplyResult(orderedProducts,
selectedProductCoupons, cartCoupon);

return new OrderSheetCouponInfo(discountsByOrderedProductId, selectedCoupons, applicableProductCoupons, applicableDeliveryFeeCoupons, cartCouponResponses);
return selectedCouponsWithCouponApplyResult;
}

private SelectedCoupons getSelectedCoupons(SelectedCouponsRequest selectedCoupons) {
Expand All @@ -94,7 +152,7 @@ private SelectedCoupons getSelectedCoupons(SelectedCouponsRequest selectedCoupon
selectedProductDuplicateCouponsByOrderedProductId.put(orderedProductId, CouponResponse.from(coupon));
} else selectedProductCouponListsByOrderedProductId.put(orderedProductId, CouponResponse.from(coupon));
}
CouponResponse cartCoupon = CouponResponse.from(getCouponJpaRepositoryById(selectedCoupons.getSelectedCartCoupons()));
CouponResponse cartCoupon = CouponResponse.from(getCouponJpaRepositoryById(selectedCoupons.getSelectedCartCouponId()));

return new SelectedCoupons(selectedProductCouponListsByOrderedProductId, selectedProductDuplicateCouponsByOrderedProductId, cartCoupon);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@

import com.programmers.smrtstore.domain.coupon.domain.entity.enums.CouponStatus;
import com.programmers.smrtstore.domain.orderManagement.order.domain.entity.Order;
import com.programmers.smrtstore.domain.orderManagement.orderedProduct.domain.entity.OrderedProduct;
import com.programmers.smrtstore.domain.user.domain.entity.User;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

Expand All @@ -15,16 +13,20 @@
@Table(name = "coupon_usage_transaction_TB")
public class CouponUsageTransaction extends CouponTransaction {

@OneToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.LAZY)
private Order order;

private CouponUsageTransaction(User user, Coupon coupon, Order order, CouponStatus couponStatus) {
@OneToOne(fetch = FetchType.LAZY)
private OrderedProduct orderedProduct;

private CouponUsageTransaction(User user, Coupon coupon, Order order,OrderedProduct orderedProduct, CouponStatus couponStatus) {
this.user = user;
this.coupon = coupon;
this.order = order;
this.orderedProduct = orderedProduct;
this.couponStatus = couponStatus;
}
public static CouponUsageTransaction of(User user, Coupon coupon, Order order, CouponStatus couponStatus) {
return new CouponUsageTransaction(user, coupon, order, couponStatus);
public static CouponUsageTransaction of(User user, Coupon coupon, Order order,OrderedProduct orderedProduct, CouponStatus couponStatus) {
return new CouponUsageTransaction(user, coupon, order, orderedProduct,couponStatus);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.programmers.smrtstore.domain.orderManagement.order.domain.entity;
package com.programmers.smrtstore.domain.orderManagement.delivery.entity;

import com.programmers.smrtstore.domain.orderManagement.order.domain.entity.vo.DeliveryAddress;
import com.programmers.smrtstore.domain.orderManagement.order.domain.entity.vo.ReceiverInfo;
import com.programmers.smrtstore.domain.orderManagement.delivery.entity.vo.DeliveryAddress;
import com.programmers.smrtstore.domain.orderManagement.delivery.entity.vo.ReceiverInfo;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
Expand All @@ -10,6 +10,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -33,7 +34,14 @@ public class DeliveryInfo {
@Column(name = "delivery_request")
private String deliveryRequest;

@Column(name = "delivery_fee")
private Integer deliveryFee;

@Builder
public DeliveryInfo(
Long id, String address1Depth, String address2Depth, String zipCode,
String receiverName, String receiverPhone, String deliveryRequest
) {
this.id = id;
this.deliveryAddress = new DeliveryAddress(address1Depth, address2Depth, zipCode);
this.receiverInfo = new ReceiverInfo(receiverName, receiverPhone);
this.deliveryRequest = deliveryRequest;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.programmers.smrtstore.domain.orderManagement.order.domain.entity.vo;
package com.programmers.smrtstore.domain.orderManagement.delivery.entity.vo;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
Expand All @@ -10,7 +10,7 @@
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class DeliveryAddress {

// TODO 대문자로 변경
@Column(name = "address_1depth")
private String address1depth;

Expand All @@ -19,4 +19,10 @@ public class DeliveryAddress {

@Column(name = "zip_code")
private String zipCode;

public DeliveryAddress(String address1depth, String address2depth, String zipCode) {
this.address1depth = address1depth;
this.address2depth = address2depth;
this.zipCode = zipCode;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.programmers.smrtstore.domain.orderManagement.order.domain.entity.vo;
package com.programmers.smrtstore.domain.orderManagement.delivery.entity.vo;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
Expand All @@ -16,4 +16,9 @@ public class ReceiverInfo {

@Column(name = "receiver_phone")
private String receiverPhone;

public ReceiverInfo(String receiverName, String receiverPhone) {
this.receiverName = receiverName;
this.receiverPhone = receiverPhone;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.programmers.smrtstore.domain.orderManagement.delivery.infrastructure;

import com.programmers.smrtstore.domain.orderManagement.delivery.entity.DeliveryInfo;
import org.springframework.data.jpa.repository.JpaRepository;

public interface DeliveryInfoJpaRepository extends JpaRepository<DeliveryInfo, Long> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.programmers.smrtstore.domain.orderManagement.order.application;

import static com.programmers.smrtstore.core.properties.ErrorCode.ORDER_NOT_FOUND;
import static com.programmers.smrtstore.core.properties.ErrorCode.USER_NOT_FOUND;

import com.programmers.smrtstore.domain.orderManagement.order.domain.entity.Order;
import com.programmers.smrtstore.domain.orderManagement.order.exception.OrderException;
import com.programmers.smrtstore.domain.orderManagement.order.infrastructure.OrderJpaRepository;
import com.programmers.smrtstore.domain.orderManagement.order.presentation.dto.res.OrderedProductResponse;
import com.programmers.smrtstore.domain.user.domain.entity.User;
import com.programmers.smrtstore.domain.user.exception.UserException;
import com.programmers.smrtstore.domain.user.infrastructure.UserJpaRepository;
import com.programmers.smrtstore.util.DateTimeUtils;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class OrderPointService {
private final UserJpaRepository userJpaRepository;
private final OrderJpaRepository orderJpaRepository;

public Integer calculateUserMonthlyTotalSpending(Long userId, int month, int year) {
checkUserExistence(userId);
DateTimeUtils.validateMonth(month);
DateTimeUtils.validateYear(year);
return orderJpaRepository.calculateMonthlyTotalSpending(userId, month, year);
}

public Integer getTotalPriceByOrderId(String orderId) {
Order order = orderJpaRepository.findByIdIncludeDeleted(orderId)
.orElseThrow(() -> new OrderException(ORDER_NOT_FOUND, String.valueOf(orderId)));
return order.getTotalPrice();
}

public List<OrderedProductResponse> getProductsForOrder(String orderId) {
return orderJpaRepository.findByIdWithOrderSheetIncludeDeleted(orderId)
.orElseThrow(() -> new OrderException(ORDER_NOT_FOUND, String.valueOf(orderId)))
.getOrderSheet().getOrderedProducts().stream()
.map(OrderedProductResponse::from)
.toList();
}

private User checkUserExistence(Long userId) {
return userJpaRepository.findById(userId)
.orElseThrow(() -> new UserException(USER_NOT_FOUND, String.valueOf(userId)));
}

}
Loading

0 comments on commit 382d4af

Please sign in to comment.