diff --git a/pom.xml b/pom.xml
index d3b60f2..ca8e00d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,13 @@
spring-boot-starter-aop
+
+
+ org.apache.commons
+ commons-lang3
+ 3.4
+
+
com.google.firebase
diff --git a/src/main/java/com/delfood/aop/AuthCheckAspect.java b/src/main/java/com/delfood/aop/AuthCheckAspect.java
index 4bd00b7..3784c68 100644
--- a/src/main/java/com/delfood/aop/AuthCheckAspect.java
+++ b/src/main/java/com/delfood/aop/AuthCheckAspect.java
@@ -1,9 +1,16 @@
package com.delfood.aop;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Objects;
import javax.servlet.http.HttpSession;
+import org.apache.commons.codec.binary.StringUtils;
import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.codehaus.commons.compiler.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
@@ -27,9 +34,8 @@ public class AuthCheckAspect {
* 로그인되어있지 않을 시 해당 메서드 로직을 중지시킨 후 리턴한다.
* @OwnerLoginCheck 해당 어노테이션이 적용된 메서드를 검사한다.
* @author jun
- * @param pjp
- * @return 로그인시 SUCCESS, 비로그인시 NO_LOGIN
- * @throws Throwable
+ * @param jp 조인포인트
+ * @throws Throwable 발생 가능한 예외
*/
@Before("@annotation(com.delfood.aop.OwnerLoginCheck)")
public void ownerLoginCheck(JoinPoint jp) throws Throwable {
@@ -49,25 +55,46 @@ public void ownerLoginCheck(JoinPoint jp) throws Throwable {
* 세션에서 사장님 로그인을 체크 한다.
* 그 후 입력받은 파라미터 값 중 매장 id를 검색하여 해당 매장이 접속한 사장님의 것인지 검사한다.
* @author jun
- * @param pjp
- * @return 비로그인시 NO_LOGIN, 해당 매장의 사장이 아닐 시 UNAUTHORIZED, 권한이 있을 시 SUCCESS
- * @throws Throwable
+ * @param jp 조인포인트
+ * @throws Throwable 발새 가능한 예외
*/
- @Before("@annotation(com.delfood.aop.OwnerShopCheck)")
- public void ownerShopCheck(JoinPoint jp) throws Throwable {
+ @Before("@annotation(com.delfood.aop.OwnerShopCheck) && @annotation(ownerShopCheck)")
+ public void ownerShopCheck(JoinPoint jp, OwnerShopCheck ownerShopCheck) throws Throwable {
log.debug("AOP - Owner Shop Check Started");
- HttpSession session = ((ServletRequestAttributes)(RequestContextHolder.currentRequestAttributes())).getRequest().getSession();
+ HttpSession session =
+ ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest()
+ .getSession();
String ownerId = SessionUtil.getLoginOwnerId(session);
-
- if(ownerId == null) {
+
+ if (ownerId == null) {
log.debug("AOP - Owner Shop Check Result - NO_LOGIN");
throw new HttpStatusCodeException(HttpStatus.UNAUTHORIZED, "NO_LOGIN") {};
}
Object[] args = jp.getArgs();
- Long shopId = (Long) args[0];
+
+ // 메소드 파라미터 추출
+ MethodSignature signature = (MethodSignature) jp.getSignature();
+ Method method = signature.getMethod();
+ Parameter[] parameters = method.getParameters();
+
+ Long shopId = null;
+
+ // 파라미터의 이름과 어노테이션의 value를 비교하여 검사
+ for (int i = 0; i < parameters.length; i++) {
+ String parameterName = parameters[i].getName();
+ if (StringUtils.equals(ownerShopCheck.value(), parameterName)) {
+ shopId = (Long) args[i];
+ }
+ }
+
+ // 어노테이션 value로 설정된 값과 같은 변수 이름이 없을 경우 예외처리
+ if (Objects.isNull(shopId)) {
+ throw new IllegalArgumentException("OwnerShopCheck 어노테이션 설정이 잘못되었습니다. value와 변수 명을 일치시켜주세요.");
+ }
+
if (!shopService.isShopOwner(shopId, ownerId)) {
log.debug("AOP - Owner Shop Check Result - UNAUTHORIZED");
@@ -78,9 +105,8 @@ public void ownerShopCheck(JoinPoint jp) throws Throwable {
/**
* 고객의 로그인을 체크한다.
* @author jun
- * @param pjp
- * @return
- * @throws Throwable
+ * @param jp 조인포인튼
+ * @throws Throwable 발생 가능한 예외
*/
@Before("@annotation(com.delfood.aop.MemberLoginCheck)")
public void memberLoginCheck(JoinPoint jp) throws Throwable {
@@ -93,4 +119,54 @@ public void memberLoginCheck(JoinPoint jp) throws Throwable {
throw new HttpStatusCodeException(HttpStatus.UNAUTHORIZED, "NO_LOGIN") {};
}
}
+
+ /**
+ * 라이더 로그인을 체크한다.
+ * @author jun
+ * @param jp 조인포인트
+ * @throws Throwable 발생 가능한 예외 설정
+ */
+ @Before("@annotation(com.delfood.aop.RiderLoginCheck)")
+ public void riderLoginCheck(JoinPoint jp) throws Throwable {
+ log.debug("AOP - Rider Login Check Started");
+
+ HttpSession session =
+ ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest()
+ .getSession();
+ String riderId = SessionUtil.getLoginRiderId(session);
+
+ if (Objects.isNull(riderId)) {
+ throw new HttpStatusCodeException(HttpStatus.UNAUTHORIZED, "RIDER_NO_LOGIN") {};
+ }
+ }
+
+ /**
+ * 공통 로그인 체크 AOP.
+ * 고객, 사장님, 라이더의 로그인 체크 기능을 하나로 모아두었다.
+ * @param jp 조인포인트
+ * @throws Throwable 발생 가능한 예외
+ */
+ @Before("@annotation(com.delfood.aop.LoginCheck) && @ annotation(loginCheck)")
+ public void loginCheck(JoinPoint jp, LoginCheck loginCheck) throws Throwable {
+ log.debug("AOP - Login Check Started");
+
+ HttpSession session =
+ ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest()
+ .getSession();
+
+ if (LoginCheck.UserType.MEMBER.equals(loginCheck.type())) {
+ memberLoginCheck(jp);
+ }
+
+ if (LoginCheck.UserType.OWNER.equals(loginCheck.type())) {
+ ownerLoginCheck(jp);
+ }
+
+ if (LoginCheck.UserType.RIDER.equals(loginCheck.type())) {
+ riderLoginCheck(jp);
+ }
+
+
+ }
+
}
diff --git a/src/main/java/com/delfood/aop/LoginCheck.java b/src/main/java/com/delfood/aop/LoginCheck.java
new file mode 100644
index 0000000..3aa4d32
--- /dev/null
+++ b/src/main/java/com/delfood/aop/LoginCheck.java
@@ -0,0 +1,28 @@
+package com.delfood.aop;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 로그인의 상태를 확인한다.
+ * 회원, 사장님, 라이더의 로그인 상태를 확인하여 로그인 되지 않았다면 예외를 발생시킨다.
+ * @author jun
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface LoginCheck {
+
+ /**
+ * 로그인을 체크하고 싶은 유저의 로그인 타입.
+ * 회원(MEMBER), 사장님(OWNER), 라이더(RIDER)중 선택할 수 있다.
+ * @return
+ */
+ UserType type();
+
+ public static enum UserType {
+ MEMBER, OWNER, RIDER
+ }
+}
diff --git a/src/main/java/com/delfood/aop/OwnerShopCheck.java b/src/main/java/com/delfood/aop/OwnerShopCheck.java
index 0034c2a..1908239 100644
--- a/src/main/java/com/delfood/aop/OwnerShopCheck.java
+++ b/src/main/java/com/delfood/aop/OwnerShopCheck.java
@@ -1,15 +1,22 @@
package com.delfood.aop;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * 매장 id가 첫 번째 파라미터로 와야한다.
+ * 매장 id를 파라미터로 주어야 한다.
* 접속한 사장님이 해당 매장의 주인인지 확인한다.
* @author yyy99
*
*/
@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
public @interface OwnerShopCheck {
-
+ /**
+ * 해당 변수의 이름.
+ * @return
+ */
+ String value();
}
diff --git a/src/main/java/com/delfood/aop/RiderLoginCheck.java b/src/main/java/com/delfood/aop/RiderLoginCheck.java
new file mode 100644
index 0000000..a7e0fb4
--- /dev/null
+++ b/src/main/java/com/delfood/aop/RiderLoginCheck.java
@@ -0,0 +1,9 @@
+package com.delfood.aop;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+public @interface RiderLoginCheck {
+
+}
diff --git a/src/main/java/com/delfood/controller/CartControllelr.java b/src/main/java/com/delfood/controller/CartControllelr.java
index c2010f2..69bdc96 100644
--- a/src/main/java/com/delfood/controller/CartControllelr.java
+++ b/src/main/java/com/delfood/controller/CartControllelr.java
@@ -1,5 +1,7 @@
package com.delfood.controller;
+import com.delfood.aop.LoginCheck;
+import com.delfood.aop.LoginCheck.UserType;
import com.delfood.aop.MemberLoginCheck;
import com.delfood.dto.ItemDTO;
import com.delfood.service.CartService;
@@ -23,31 +25,31 @@ public class CartControllelr {
private CartService cartService;
@PostMapping("/members/cart/menus")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public void addMenu(@RequestBody ItemDTO item, HttpSession session) {
cartService.addOrdersItem(item, SessionUtil.getLoginMemberId(session));
}
@GetMapping("/members/cart/menus")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public List getCart(HttpSession session) {
return cartService.getItems(SessionUtil.getLoginMemberId(session));
}
@DeleteMapping("/members/cart/menus")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public void clearCart(HttpSession session) {
cartService.claer(SessionUtil.getLoginMemberId(session));
}
@DeleteMapping("/members/cart/menus/{index}")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public void deleteCartMenu(HttpSession session, @PathVariable long index) {
cartService.deleteCartMenu(SessionUtil.getLoginMemberId(session), index);
}
@GetMapping("/members/cart/price")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public CartPriceResponse cartPrice(HttpSession session) {
String memberId = SessionUtil.getLoginMemberId(session);
return new CartPriceResponse(cartService.getItems(memberId), cartService.allPrice(memberId));
diff --git a/src/main/java/com/delfood/controller/CouponController.java b/src/main/java/com/delfood/controller/CouponController.java
new file mode 100644
index 0000000..c36f6c0
--- /dev/null
+++ b/src/main/java/com/delfood/controller/CouponController.java
@@ -0,0 +1,78 @@
+package com.delfood.controller;
+
+import com.delfood.dto.CouponDTO;
+import com.delfood.service.CouponService;
+import lombok.extern.log4j.Log4j2;
+import java.time.LocalDateTime;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Log4j2
+@RestController
+@RequestMapping("/coupons/")
+public class CouponController {
+
+ @Autowired
+ CouponService couponService;
+
+ /**
+ * 쿠폰을 추가한다.
+ * @param couponInfo 쿠폰 정보
+ * @return
+ *
+ * @author jinyoung
+ */
+ @PostMapping
+ public void addCoupon(@RequestBody CouponDTO couponInfo) {
+
+ if (CouponDTO.hasNullData(couponInfo)) {
+ log.error("insufficient coupon information! {}", couponInfo.toString());
+ throw new NullPointerException("insufficient coupon information! " + couponInfo.toString());
+ }
+
+ couponService.addCoupon(couponInfo);
+ }
+
+ /**
+ * 쿠폰 이름과 만료일을 수정한다.
+ *
+ * @param id 쿠폰 아이디
+ * @param name 수정할 쿠폰 이름
+ * @param endAt 수정할 만료일
+ *
+ * @author jinyoung
+ */
+ @PatchMapping
+ public void updateCouponNameAndEndAt(Long id, String name, LocalDateTime endAt) {
+ couponService.updateCouponNameAndEndAt(id, name, endAt);
+ }
+
+ /**
+ * 쿠폰을 삭제한다.
+ *
+ * @param id 쿠폰 아이디
+ */
+ public void deleteCoupon(Long id) {
+ couponService.deleteCoupon(id);
+ }
+
+
+ /**
+ * 만료일이 지나지 않은 쿠폰들을 조회한다.
+ * @return 쿠폰리스트
+ *
+ * @author jinyoung
+ */
+ @GetMapping
+ public List getAvailableCoupons() {
+ return couponService.getAvaliableCoupons();
+ }
+
+}
diff --git a/src/main/java/com/delfood/controller/CouponIssueController.java b/src/main/java/com/delfood/controller/CouponIssueController.java
new file mode 100644
index 0000000..d1dcccb
--- /dev/null
+++ b/src/main/java/com/delfood/controller/CouponIssueController.java
@@ -0,0 +1,53 @@
+package com.delfood.controller;
+
+import com.delfood.aop.LoginCheck;
+import com.delfood.aop.LoginCheck.UserType;
+import com.delfood.aop.MemberLoginCheck;
+import com.delfood.dto.CouponIssueDTO;
+import com.delfood.service.CouponIssueService;
+import com.delfood.utils.SessionUtil;
+import java.util.List;
+import javax.servlet.http.HttpSession;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+@Log4j2
+@RestController
+@RequestMapping("/couponIssues/")
+public class CouponIssueController {
+
+ @Autowired
+ private CouponIssueService couponIssueService;
+
+ /**
+ * 회원에게 쿠폰을 발행한다.
+ * @param session 현재 사용자 세션
+ * @param couponId 쿠폰 아이디
+ */
+ @PostMapping
+ @ResponseStatus(HttpStatus.CREATED)
+ @LoginCheck(type = UserType.MEMBER)
+ public void addCouponIssue(HttpSession session, @RequestBody Long couponId) {
+
+ couponIssueService.createCouponIssue(SessionUtil.getLoginMemberId(session), couponId);
+ }
+
+ /**
+ * 회원이 가지고 있는 발행 쿠폰들을 조회한다.
+ * @param session 현재 사용자 세션
+ * @return
+ */
+ @GetMapping
+ @LoginCheck(type = UserType.MEMBER)
+ public List getCouponIssues(HttpSession session) {
+ return couponIssueService.getCouponIssues(SessionUtil.getLoginMemberId(session));
+ }
+
+}
diff --git a/src/main/java/com/delfood/controller/LocationController.java b/src/main/java/com/delfood/controller/LocationController.java
index 23c0dcb..d9657bb 100644
--- a/src/main/java/com/delfood/controller/LocationController.java
+++ b/src/main/java/com/delfood/controller/LocationController.java
@@ -43,7 +43,7 @@ public class LocationController {
* @return
*/
@PostMapping("deliveries/{shopId}/possibles")
- @OwnerShopCheck
+ @OwnerShopCheck("shopId")
@ResponseStatus(HttpStatus.CREATED)
public void addDeliveryLocation(
@PathVariable(name = "shopId") Long shopId,
@@ -60,7 +60,7 @@ public void addDeliveryLocation(
* @return
*/
@GetMapping("deliveries/{shopId}/possibles")
- @OwnerShopCheck
+ @OwnerShopCheck("shopId")
public List getDeliveryLocations(
@PathVariable(name = "shopId") Long shopId) {
return shopService.getDeliveryLocations(shopId);
@@ -76,7 +76,7 @@ public List getDeliveryLocations(
* @return
*/
@DeleteMapping("deliveries/{shopId}/possibles/{deliveryLocationId}")
- @OwnerShopCheck
+ @OwnerShopCheck("shopId")
public void deleteDeliveryLocation(
@PathVariable(value = "shopId") Long shopId,
@PathVariable(value = "deliveryLocationId") Long deliveryLocationId,
diff --git a/src/main/java/com/delfood/controller/MemberController.java b/src/main/java/com/delfood/controller/MemberController.java
index eb75318..82935ec 100644
--- a/src/main/java/com/delfood/controller/MemberController.java
+++ b/src/main/java/com/delfood/controller/MemberController.java
@@ -1,5 +1,7 @@
package com.delfood.controller;
+import com.delfood.aop.LoginCheck;
+import com.delfood.aop.LoginCheck.UserType;
import com.delfood.aop.MemberLoginCheck;
import com.delfood.dto.MemberDTO;
import com.delfood.error.exception.DuplicateIdException;
@@ -69,7 +71,7 @@ public class MemberController {
* @return MemberDTO
*/
@GetMapping("myInfo")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public MemberInfoResponse memberInfo(HttpSession session) {
String id = SessionUtil.getLoginMemberId(session);
MemberDTO memberInfo = memberService.getMemberInfo(id);
@@ -149,7 +151,7 @@ public ResponseEntity login(@RequestBody @NonNull MemberLoginRequ
* @return 로그인 하지 않았을 시 401코드를 반환하고 result:NO_LOGIN 반환 로그아웃 성공시 200 코드를 반환
*/
@GetMapping("logout")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public void logout(HttpSession session) {
SessionUtil.logoutMember(session);
}
@@ -162,7 +164,7 @@ public void logout(HttpSession session) {
* @return
*/
@PatchMapping("password")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public void updateMemberInfo(HttpSession session,
@RequestBody @NotNull UpdateMemberPasswordRequest passwordRequest) {
String passwordBeforeChange = passwordRequest.getPasswordBeforeChange();
@@ -183,7 +185,7 @@ public void updateMemberInfo(HttpSession session,
* @return
*/
@DeleteMapping("myInfo")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public void deleteMemberInfo(HttpSession session) {
String id = SessionUtil.getLoginMemberId(session);
memberService.deleteMember(id);
@@ -198,7 +200,7 @@ public void deleteMemberInfo(HttpSession session) {
* @param session 현재 로그인한 고객의 세션
*/
@PatchMapping("address")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public ResponseEntity updateMemberAddress(
@RequestBody @NotNull UpdateMemberAddressRequest memberInfo, HttpSession session) {
ResponseEntity responseEntity = null;
@@ -225,7 +227,7 @@ public ResponseEntity updateMemberAddress(
}
@PostMapping("token")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public void addToken(HttpSession session, String token) {
String memberId = SessionUtil.getLoginMemberId(session);
pushService.addMemberToken(memberId, token);
diff --git a/src/main/java/com/delfood/controller/OrderController.java b/src/main/java/com/delfood/controller/OrderController.java
index d650297..2720bfe 100644
--- a/src/main/java/com/delfood/controller/OrderController.java
+++ b/src/main/java/com/delfood/controller/OrderController.java
@@ -1,22 +1,32 @@
package com.delfood.controller;
+import com.delfood.aop.LoginCheck;
+import com.delfood.aop.LoginCheck.UserType;
import com.delfood.aop.MemberLoginCheck;
+import com.delfood.aop.OwnerLoginCheck;
import com.delfood.controller.response.OrderResponse;
import com.delfood.dto.ItemsBillDTO;
import com.delfood.dto.OrderDTO;
import com.delfood.dto.OrderItemDTO;
+import com.delfood.error.exception.coupon.IssuedCouponExistException;
import com.delfood.error.exception.order.TotalPriceMismatchException;
import com.delfood.dto.OrderBillDTO;
+import com.delfood.service.CouponIssueService;
import com.delfood.service.OrderService;
+import com.delfood.service.PushService;
+import com.delfood.service.ShopService;
import com.delfood.utils.SessionUtil;
+import java.time.LocalDateTime;
import java.util.List;
import javax.servlet.http.HttpSession;
-import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Getter;
+import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import org.codehaus.commons.nullanalysis.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -31,16 +41,28 @@ public class OrderController {
@Autowired
OrderService orderService;
+ @Autowired
+ ShopService shopService;
+
+ @Autowired
+ PushService pushService;
+
+ @Autowired
+ CouponIssueService couponIssueService;
+
/**
* 아이템들의 가격과 정보를 조회한다.
+ * 쿠폰과 배달 가격을 제외한 순수 아이템 가격만 제공한다.
* @author jun
* @param items 가격을 계산할 아이템들
* @return
*/
@GetMapping("price")
- @MemberLoginCheck
- public long getItemsBill(HttpSession session, @RequestBody List items) {
- return orderService.totalPrice(SessionUtil.getLoginMemberId(session), items);
+ @LoginCheck(type = UserType.MEMBER)
+ public ItemsBillResponse getItemsBill(HttpSession session,
+ @RequestBody List items) {
+ long itemsPrice = orderService.totalPrice(SessionUtil.getLoginMemberId(session), items);
+ return ItemsBillResponse.builder().itemsPrice(itemsPrice).build();
}
/**
@@ -50,7 +72,7 @@ public long getItemsBill(HttpSession session, @RequestBody List it
* @return
*/
@GetMapping("{orderId}/bill")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public OrderBillDTO orderInfo(@PathVariable("orderId") Long orderId) {
return orderService.getPreOrderBill(orderId);
}
@@ -63,7 +85,7 @@ public OrderBillDTO orderInfo(@PathVariable("orderId") Long orderId) {
* @return
*/
@PostMapping
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public OrderResponse order(HttpSession session, @RequestBody OrderRequest request) {
if (request.getItems().isEmpty()) {
// items가 null일때도 NullpointerException이 발생한다
@@ -74,31 +96,49 @@ public OrderResponse order(HttpSession session, @RequestBody OrderRequest reques
if (orderService.isShopItems(request.getItems(), request.getShopId()) == false) {
log.error("주문하신 매장의 메뉴 또는 옵션이 아닙니다.");
throw new IllegalArgumentException("주문하신 매장의 메뉴 또는 옵션이 아닙니다.");
- }
+ }
+
+ // 쿠폰이 유효한지 검증
+ if (couponIssueService.isUsed(request.getCouponIssueId())) {
+ log.info("이미 사용한 쿠폰 사용 시도. 요청 발행 쿠폰 아이디 : {}", request.getCouponIssueId());
+ throw new IssuedCouponExistException("이미 사용한 쿠폰입니다");
+ }
+
// 클라이언트가 계산한 금액과 서버에서 계산한 금액이 같은지 비교
- long totalPriceFromServer =
- orderService.totalPrice(SessionUtil.getLoginMemberId(session), request.getItems());
- if (totalPriceFromServer != request.getTotalPrice()) {
- log.error("Total Price Mismatch! client price : {}, server price : {}",
- request.getTotalPrice(),
- totalPriceFromServer);
+ long totalItemsPriceFromServer = orderService.totalPrice(SessionUtil.getLoginMemberId(session),
+ request.getItems());
+ long discountPriceFromServer =
+ couponIssueService.discountPrice(request.getCouponIssueId(), totalItemsPriceFromServer);
+ long totalPrice = totalItemsPriceFromServer - discountPriceFromServer;
+ if (totalPrice != request.getTotalPrice()) {
+ log.error(
+ "Total Price Mismatch! client price : {}, server price : {},"
+ + " totalItemsPriceFromServer : {}, discountPriceFromServer : {}",
+ request.getTotalPrice(), totalPrice, totalItemsPriceFromServer, discountPriceFromServer);
throw new TotalPriceMismatchException("Total Price Mismatch!");
}
- return orderService.order(SessionUtil.getLoginMemberId(session), request.getItems(),
- request.getShopId());
+ OrderResponse orderResponse = orderService.order(SessionUtil.getLoginMemberId(session),
+ request.getItems(), request.getShopId(), request.getCouponIssueId());
+
+ return orderResponse;
}
/**
* 아이템 리스트들을 상세하게 계산서로 발행한다.
* @param session 사용자의 세션
- * @param items 주문하기 전 아이템들
+ * @param billRequest 주문할 아이템들, 쿠폰정보. 쿠폰정보는 Null 가능
* @return
*/
@GetMapping("bill")
- @MemberLoginCheck
- public ItemsBillDTO getBill(HttpSession session, @RequestBody List items) {
- return orderService.getBill(SessionUtil.getLoginMemberId(session), items);
+ @LoginCheck(type = UserType.MEMBER)
+ public ItemsBillDTO getBill(HttpSession session, @RequestBody BillRequest billRequest) {
+ if (couponIssueService.isUsed(billRequest.getCouponIssueId())) {
+ log.info("이미 사용한 쿠폰 사용 시도. 요청 발행 쿠폰 아이디 : {}", billRequest.getCouponIssueId());
+ throw new IssuedCouponExistException("이미 사용한 쿠폰입니다");
+ }
+ return orderService.getBill(SessionUtil.getLoginMemberId(session), billRequest.getItems(),
+ billRequest.getCouponIssueId());
}
/**
@@ -109,7 +149,7 @@ public ItemsBillDTO getBill(HttpSession session, @RequestBody List
* @return
*/
@GetMapping
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public List myOrders(HttpSession session, @Nullable Long lastViewedOrderId) {
return orderService.getMemberOrder(SessionUtil.getLoginMemberId(session), lastViewedOrderId);
}
@@ -122,7 +162,7 @@ public List myOrders(HttpSession session, @Nullable Long lastViewedOrd
* @return
*/
@GetMapping("{orderId}")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public OrderDTO getOrder(HttpSession session, @PathVariable Long orderId) {
OrderDTO orderInfo = orderService.getOrder(orderId);
if (orderInfo == null) {
@@ -137,11 +177,79 @@ public OrderDTO getOrder(HttpSession session, @PathVariable Long orderId) {
return orderInfo;
}
+
+
+ // 여기서 부터는 사장님 관련 컨트롤러입니다.
+
+ /**
+ * 사장님이 소유한 가게에 요청된 주문들을 조회한다.
+ * 유효한 주문만 조회된다.
+ * @author jun
+ * @return
+ */
+ @GetMapping("owner")
+ @LoginCheck(type = UserType.OWNER)
+ public List getRequestedOrders(HttpSession session) {
+ String ownerId = SessionUtil.getLoginOwnerId(session);
+ List shopOrders = orderService.getOwnerOrderRequest(ownerId);
+ return shopOrders;
+ }
+
+ /**
+ * 주문을 승인한다.
+ * @author jun
+ * @param orderId 주문 아이디
+ * @param request 주문 승낙시 입력해야하는 정보
+ * @param session 사장님 세션
+ */
+ @PatchMapping("{orderId}/approve")
+ @LoginCheck(type = UserType.OWNER)
+ public void orderApprove(@PathVariable(name = "orderId") Long orderId,
+ @RequestBody OrderApproveRequest request,
+ HttpSession session) {
+ String ownerId = SessionUtil.getLoginOwnerId(session);
+
+ // 해당 주문에 대한 권한이 있는지 확인한다
+ if (orderService.isOwnerOrder(ownerId, orderId) == false) {
+ throw new IllegalArgumentException("해당 주문에 대한 권한이 없습니다.");
+ }
+
+ // 주문 승인을 진행한다
+ orderService.orderApprove(orderId, request.getMinute());
+ }
+
+
// request
@Getter
private static class OrderRequest {
+ @NonNull
private Long shopId;
+ @NonNull
private List items;
+ @Nullable
+ private Long couponIssueId;
private long totalPrice;
}
+
+ @Getter
+ private static class BillRequest {
+ private List items;
+ @Nullable
+ private Long couponIssueId;
+ }
+
+ @Getter
+ private static class OrderApproveRequest {
+ @NonNull
+ private Long minute; // 몇분이나 걸릴지 입력한 값
+
+ }
+
+ // response
+
+ @Builder
+ @Getter
+ private static class ItemsBillResponse {
+ private long itemsPrice;
+ }
}
diff --git a/src/main/java/com/delfood/controller/OwnerController.java b/src/main/java/com/delfood/controller/OwnerController.java
index efe1ceb..fec58da 100644
--- a/src/main/java/com/delfood/controller/OwnerController.java
+++ b/src/main/java/com/delfood/controller/OwnerController.java
@@ -1,5 +1,7 @@
package com.delfood.controller;
+import com.delfood.aop.LoginCheck;
+import com.delfood.aop.LoginCheck.UserType;
import com.delfood.aop.MemberLoginCheck;
import com.delfood.aop.OwnerLoginCheck;
import com.delfood.dto.OwnerDTO;
@@ -107,7 +109,7 @@ public ResponseEntity login(@RequestBody OwnerLoginRequest l
* @return
*/
@GetMapping("logout")
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public void logout(HttpSession session) {
SessionUtil.logoutOwner(session);
}
@@ -120,7 +122,7 @@ public void logout(HttpSession session) {
* @return
*/
@GetMapping("myInfo")
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public OwnerInfoResponse ownerInfo(HttpSession session) {
String id = SessionUtil.getLoginOwnerId(session);
OwnerDTO ownerInfo = ownerService.getOwner(id);
@@ -135,7 +137,7 @@ public OwnerInfoResponse ownerInfo(HttpSession session) {
* @return
*/
@PatchMapping
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public void updateOwnerInfo(
@RequestBody UpdateOwnerMailAndTelRequest updateRequest, HttpSession session) {
@@ -159,7 +161,7 @@ public void updateOwnerInfo(
* @return
*/
@PatchMapping("password")
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public void updatePassword(
@RequestBody UpdateOwnerPasswordRequest passwordResquest, HttpSession session) {
String id = SessionUtil.getLoginOwnerId(session);
@@ -173,7 +175,7 @@ public void updatePassword(
}
@PostMapping("token")
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public void addToken(HttpSession session, String token) {
String ownerId = SessionUtil.getLoginOwnerId(session);
pushService.addOwnerToken(ownerId, token);
diff --git a/src/main/java/com/delfood/controller/RiderController.java b/src/main/java/com/delfood/controller/RiderController.java
new file mode 100644
index 0000000..6164206
--- /dev/null
+++ b/src/main/java/com/delfood/controller/RiderController.java
@@ -0,0 +1,164 @@
+package com.delfood.controller;
+
+import com.delfood.aop.LoginCheck;
+import com.delfood.aop.LoginCheck.UserType;
+import com.delfood.aop.RiderLoginCheck;
+import com.delfood.dto.rider.RiderDTO;
+import com.delfood.service.rider.RiderInfoService;
+import com.delfood.utils.SessionUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.Objects;
+import javax.servlet.http.HttpSession;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+@Log4j2
+@RestController
+@RequestMapping("/riders/")
+public class RiderController {
+
+ @Autowired
+ private RiderInfoService riderInfoService;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ /**
+ * 아이디 중복 체크.
+ * @author jun
+ * @param riderId 중복체크할 아이디
+ * @return 중복된 아이디라면 true
+ */
+ @GetMapping("duplicated/id/{riderId}")
+ public boolean isDuplicatedId(@PathVariable(name = "riderId") String riderId) {
+ return riderInfoService.isDuplicatedId(riderId);
+ }
+
+ /**
+ * 라이더 회원가입.
+ * @author jun
+ * @param riderInfo 회원가입할 아이디 정보
+ * @throws JsonProcessingException 로그를 기록할 때 직렬화중 생길 수 있는 예외
+ */
+ @PostMapping("signUp")
+ @ResponseStatus(code = HttpStatus.CREATED)
+ public void signUp(@RequestBody RiderDTO riderInfo) throws JsonProcessingException {
+ if (riderInfo.hasNullData()) {
+ log.info("회원가입 필수 데이터 누락. 요청 정보 : {}", objectMapper.writeValueAsString(riderInfo));
+ throw new NullPointerException("라이더 회원가입에 필수 데이터가 누락되었습니다.");
+ }
+
+ RiderDTO encryptRiderInfo = RiderDTO.encryptDTO(riderInfo);
+ riderInfoService.signUp(encryptRiderInfo);
+ }
+
+ /**
+ * 라이더 로그인을 진행한다.
+ *
+ * @author jun
+ * @param request id, password 정보
+ * @param session 현재 세션
+ * @return
+ */
+ @PostMapping("login")
+ public RiderDTO signIn(@RequestBody SignInRequest request, HttpSession session) {
+ if (Objects.isNull(SessionUtil.getLoginRiderId(session)) == false) {
+ logout(session);
+ }
+
+ RiderDTO riderInfo = riderInfoService.signIn(request.getId(), request.getPassword());
+ SessionUtil.setLoginRiderId(session, riderInfo.getId());
+ return riderInfo;
+ }
+
+
+ /**
+ * 라이더 로그아웃을 진행한다.
+ * @author jun
+ * @param session 사용자의 세션
+ */
+ @GetMapping("logout")
+ public void logout(HttpSession session) {
+ SessionUtil.logoutRider(session);
+ }
+
+ /**
+ * 라이더의 비밀번호를 변경한다.
+ * @param session 사용자의 세션
+ * @param request 변경전 비밀번호, 변경할 비밀번호 정보
+ */
+ @PatchMapping("password")
+ @LoginCheck(type = UserType.RIDER)
+ public void updatePassword(HttpSession session, @RequestBody UpdatePasswordRequest request) {
+ String id = SessionUtil.getLoginRiderId(session);
+ riderInfoService.changePassword(id, request.getPasswordBeforechange(),
+ request.getPasswordAfterChange());
+ }
+
+ /**
+ * 라이더의 계정을 삭제한다.
+ * 삭제가 완료된다면 로그아웃된다.
+ * @param session 현제 사용자의 세션
+ * @param password 유효성 검사를 위한 계정 비밀번호
+ */
+ @DeleteMapping
+ @LoginCheck(type = UserType.RIDER)
+ public void deleteRiderAccount(HttpSession session, String password) {
+ String id = SessionUtil.getLoginRiderId(session);
+ riderInfoService.deleteAccount(id, password);
+ SessionUtil.logoutRider(session);
+ }
+
+ @PatchMapping("mail")
+ public void updateMail(HttpSession session, @RequestBody UpdateMailRequest request) {
+ String id = SessionUtil.getLoginRiderId(session);
+ riderInfoService.changeMail(id, request.getPassword(), request.getUpdateMail());
+ }
+
+
+
+ // Request
+ @Getter
+ private static class SignInRequest {
+ @NonNull
+ private String id;
+
+ @NonNull
+ private String password;
+ }
+
+ @Getter
+ private static class UpdatePasswordRequest {
+ @NonNull
+ private String passwordBeforechange;
+
+ @NonNull
+ private String passwordAfterChange;
+ }
+
+ @Getter
+ private static class UpdateMailRequest {
+ @NonNull
+ private String password;
+
+ @NonNull
+ private String updateMail;
+ }
+
+
+
+}
diff --git a/src/main/java/com/delfood/controller/ShopController.java b/src/main/java/com/delfood/controller/ShopController.java
index a7bd6f1..aad5125 100644
--- a/src/main/java/com/delfood/controller/ShopController.java
+++ b/src/main/java/com/delfood/controller/ShopController.java
@@ -15,8 +15,10 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import com.delfood.aop.LoginCheck;
import com.delfood.aop.OwnerLoginCheck;
import com.delfood.aop.OwnerShopCheck;
+import com.delfood.aop.LoginCheck.UserType;
import com.delfood.dto.AddressDTO;
import com.delfood.dto.DeliveryLocationDTO;
import com.delfood.dto.OwnerDTO;
@@ -48,7 +50,7 @@ public class ShopController {
* @return
*/
@PostMapping
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public ResponseEntity addShop(HttpSession session,
@RequestBody ShopDTO shopInfo) {
String ownerId = SessionUtil.getLoginOwnerId(session);
@@ -71,7 +73,7 @@ public ResponseEntity addShop(HttpSession session,
* @return 페이지에 따른 사장님 매장, 총 매장 개수
*/
@GetMapping
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public MyShopsResponse myShops(MyShopsRequest myShopsRequest,
HttpSession session) {
String id = SessionUtil.getLoginOwnerId(session);
@@ -90,7 +92,7 @@ public MyShopsResponse myShops(MyShopsRequest myShopsRequest,
* @return
*/
@PatchMapping("{id}")
- @OwnerShopCheck
+ @OwnerShopCheck("id")
public void updateShop(@PathVariable Long id,
@RequestBody(required = true) final ShopUpdateDTO updateInfo, HttpSession session) {
final ShopUpdateDTO copyData = ShopUpdateDTO.copyWithId(updateInfo, id);
@@ -107,7 +109,7 @@ public void updateShop(@PathVariable Long id,
* @return
*/
@PatchMapping("open/{id}")
- @OwnerShopCheck
+ @OwnerShopCheck("id")
public ShopDTO openShop(
@PathVariable(value = "id", required = true) Long id, HttpSession session) {
shopService.openShop(id);
@@ -123,7 +125,7 @@ public ShopDTO openShop(
* @return 오픈한 매장의 id, 이름
*/
@PatchMapping("open/")
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public List openAllShops(HttpSession session) {
String ownerId = SessionUtil.getLoginOwnerId(session);
List openShops = shopService.openAllShops(ownerId);
@@ -140,7 +142,7 @@ public List openAllShops(HttpSession session) {
* @return
*/
@PatchMapping("close/{id}")
- @OwnerShopCheck
+ @OwnerShopCheck("id")
public ShopDTO closeShop(
@PathVariable(value = "id", required = true) Long id, HttpSession session) {
shopService.closeShop(id);
@@ -156,7 +158,7 @@ public ShopDTO closeShop(
* @return 운영 종료를 진행한 매장의 id, 이름
*/
@PatchMapping("close/")
- @OwnerLoginCheck
+ @LoginCheck(type = UserType.OWNER)
public List closeAllShops(HttpSession session) {
String ownerId = SessionUtil.getLoginOwnerId(session);
return shopService.closeAllShops(ownerId);
@@ -170,7 +172,7 @@ public List closeAllShops(HttpSession session) {
* @return
*/
@GetMapping("{shopId}")
- @OwnerShopCheck
+ @OwnerShopCheck("shopId")
public ShopInfoResponse shopInfo(
@PathVariable(value = "shopId", required = true) Long shopId, HttpSession session) {
ShopDTO shopInfo = shopService.getShop(shopId);
diff --git a/src/main/java/com/delfood/controller/ShopSearchController.java b/src/main/java/com/delfood/controller/ShopSearchController.java
index 64ab6d7..f76ade3 100644
--- a/src/main/java/com/delfood/controller/ShopSearchController.java
+++ b/src/main/java/com/delfood/controller/ShopSearchController.java
@@ -1,5 +1,7 @@
package com.delfood.controller;
+import com.delfood.aop.LoginCheck;
+import com.delfood.aop.LoginCheck.UserType;
import com.delfood.aop.MemberLoginCheck;
import com.delfood.dto.ShopCategoryDTO;
import com.delfood.dto.ShopDTO;
@@ -52,7 +54,7 @@ public GetShopCategoriesResponse getShopCategories() {
* @return
*/
@GetMapping("/available/shops")
- @MemberLoginCheck
+ @LoginCheck(type = UserType.MEMBER)
public GetShopByCategoryIdAndTownCodeResponse getShopsByCategoryIdAndTownCode(
@RequestParam(required = true) Long categoryId, HttpSession session) {
String memberId = SessionUtil.getLoginMemberId(session);
diff --git a/src/main/java/com/delfood/dao/FcmDao.java b/src/main/java/com/delfood/dao/FcmDao.java
index 869ddee..3efe483 100644
--- a/src/main/java/com/delfood/dao/FcmDao.java
+++ b/src/main/java/com/delfood/dao/FcmDao.java
@@ -1,7 +1,9 @@
package com.delfood.dao;
+import com.delfood.dto.push.PushMessageForOne;
import com.delfood.utils.RedisKeyFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.firebase.messaging.Message;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -108,6 +110,15 @@ public List getOwnerTokens(String ownerId) {
.map(e -> objectMapper.convertValue(e, String.class))
.collect(Collectors.toList());
}
+
+ public void addMemberErrorPush(String memberId, List messages) {
+ redisTemplate.opsForList().rightPush(RedisKeyFactory.generateFcmMemberErrorKey(memberId),
+ messages);
+ }
+ public void addOwnerErrorPush(String ownerId, List messages) {
+ redisTemplate.opsForList().rightPush(RedisKeyFactory.generateFcmOwnerErrorKey(ownerId),
+ messages);
+ }
}
diff --git a/src/main/java/com/delfood/dto/CouponDTO.java b/src/main/java/com/delfood/dto/CouponDTO.java
new file mode 100644
index 0000000..b332dc3
--- /dev/null
+++ b/src/main/java/com/delfood/dto/CouponDTO.java
@@ -0,0 +1,58 @@
+package com.delfood.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonFormat.Shape;
+import java.time.LocalDateTime;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import org.apache.ibatis.type.Alias;
+
+@ToString
+@Getter
+@Setter
+@Alias("coupon")
+public class CouponDTO {
+
+ public enum DiscountType {
+ WON, PERCENT
+ }
+
+ public enum Status {
+ DEFAULT, DELETED
+ }
+
+ private Long id;
+
+ private String name;
+
+ private DiscountType discountType;
+
+ private Long discountValue;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime createdAt;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime updatedAt;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime endAt;
+
+ private Status status;
+
+ /**
+ * 쿠폰 등록에 필요한 내용이 null인지 확인.
+ * @param couponInfo 쿠폰정보
+ * @return
+ *
+ * @author jinyoung
+ */
+ public static boolean hasNullData(CouponDTO couponInfo) {
+ return couponInfo.getName() == null || couponInfo.getDiscountType() == null
+ || couponInfo.getDiscountValue() == null || couponInfo.getEndAt() == null;
+
+ }
+}
diff --git a/src/main/java/com/delfood/dto/CouponIssueDTO.java b/src/main/java/com/delfood/dto/CouponIssueDTO.java
new file mode 100644
index 0000000..2525dbe
--- /dev/null
+++ b/src/main/java/com/delfood/dto/CouponIssueDTO.java
@@ -0,0 +1,49 @@
+package com.delfood.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.time.LocalDateTime;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import org.apache.ibatis.type.Alias;
+
+@Setter
+@Getter
+@ToString
+@Alias("couponIssue")
+public class CouponIssueDTO {
+
+ public enum Status {
+ DEFAULT, USED
+ }
+
+ public enum DiscountType {
+ WON, PERCENT
+ }
+
+ private Long id;
+
+ private String memberId;
+
+ private Long couponId;
+
+ private Status status;
+
+ private Long paymentId;
+
+ private DiscountType discountType;
+
+ private String name;
+
+ private Long discountValue;
+
+ @JsonFormat(pattern = "yy-MM-dd hh:mm:ss")
+ private LocalDateTime createdAt;
+
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime endAt;
+
+}
diff --git a/src/main/java/com/delfood/dto/ItemDTO.java b/src/main/java/com/delfood/dto/ItemDTO.java
index 416c743..7a87817 100644
--- a/src/main/java/com/delfood/dto/ItemDTO.java
+++ b/src/main/java/com/delfood/dto/ItemDTO.java
@@ -2,12 +2,15 @@
import java.util.List;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@EqualsAndHashCode(of = {"menuInfo", "options", "shopInfo"})
+@NoArgsConstructor
+@AllArgsConstructor
public class ItemDTO {
private CacheMenuDTO menuInfo; // id, name, price
private List options; // id, name, price
@@ -30,6 +33,8 @@ public boolean hasNullDataBeforeInsertCart() {
@Getter
@EqualsAndHashCode
+ @NoArgsConstructor
+ @AllArgsConstructor
public static class CacheMenuDTO {
private Long id;
private String name;
@@ -38,6 +43,8 @@ public static class CacheMenuDTO {
@Getter
@EqualsAndHashCode
+ @NoArgsConstructor
+ @AllArgsConstructor
public static class CacheShopDTO {
private Long id;
private String name;
@@ -45,6 +52,7 @@ public static class CacheShopDTO {
@Getter
@EqualsAndHashCode
+ @AllArgsConstructor
public static class CacheOptionDTO {
private Long id;
private String name;
diff --git a/src/main/java/com/delfood/dto/ItemsBillDTO.java b/src/main/java/com/delfood/dto/ItemsBillDTO.java
index 53af7ce..2856503 100644
--- a/src/main/java/com/delfood/dto/ItemsBillDTO.java
+++ b/src/main/java/com/delfood/dto/ItemsBillDTO.java
@@ -1,19 +1,29 @@
package com.delfood.dto;
+import java.time.LocalDateTime;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
+import org.codehaus.jackson.annotate.JsonIgnore;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
+import lombok.extern.log4j.Log4j2;
// 사용자에게 전달하는 최종 주문서 DTO
@Getter
@NoArgsConstructor
+@Log4j2
public class ItemsBillDTO {
@NonNull
private List menus;
+ private long itemsPrice;
+
+ private long discountPrice;
+
private long totalPrice;
@NonNull
private String memberId;
@@ -24,6 +34,8 @@ public class ItemsBillDTO {
private DeliveryInfo deliveryInfo;
+ private CouponInfo couponInfo;
+
/**
* 해당 인자를 세팅하여 새로운 객체를 반환한다.
* 리스트인 'menus'에는 ArrayList를 할당한다.
@@ -36,8 +48,9 @@ public ItemsBillDTO(@NonNull String memberId,
@NonNull ShopInfo shopInfo,
double distanceMeter,
long deliveryPrice,
- long itemsPrice,
- List menus) {
+ List menus,
+ CouponInfo couponInfo,
+ List ordersItems) {
this.memberId = memberId;
this.addressInfo = addressInfo;
this.shopInfo = shopInfo;
@@ -45,7 +58,30 @@ public ItemsBillDTO(@NonNull String memberId,
.deliveryPrice(deliveryPrice)
.build();
this.menus = menus;
- this.totalPrice = totalPrice();
+ this.couponInfo = couponInfo;
+
+ // 아이템 개수 맞춰주기
+ log.debug("아이템 개수 맞추기 시작");
+ ordersItems.stream().forEach(item -> {
+ menus.stream().forEach(menu -> {
+ log.debug("비교 메뉴 1 : {}, 비교 메뉴 2 : {}", menu.getId(), item.getMenuId());
+ log.debug("비교 옵션 1 : {}, 비교 옵션 2 : {}",
+ item.getOptions().stream().mapToLong(e -> e.getOptionId()).sorted().toArray(),
+ menu.getOptions().stream().mapToLong(e -> e.getId()).sorted().toArray());
+ log.debug("메뉴 비교 결과 : {}, 옵션 비교 결과 : {}", menu.getId() == item.getMenuId(),
+ item.getOptions().stream().mapToLong(e -> e.getOptionId()).sorted().toArray()
+ .equals(menu.getOptions().stream().mapToLong(e -> e.getId()).sorted().toArray()));
+ if (menu.getId() == item.getMenuId() && Arrays.equals(
+ item.getOptions().stream().mapToLong(e -> e.getOptionId()).sorted().toArray(),
+ menu.getOptions().stream().mapToLong(e -> e.getId()).sorted().toArray())) {
+ log.debug("같은 아이템 발견. 카운트 : {} ", item.getCount());
+ menu.count = item.getCount();
+ }
+ });
+ });
+ log.debug("아이템 개수 맞추기 끝");
+
+ totalPrice();
}
@Getter
@@ -55,6 +91,7 @@ public static class MenuInfo {
private String name;
private long price;
private List options;
+ private long count;
/**
* 메뉴 정보의 간략한 정보를 저장하는 DTO를 생성한다.
@@ -63,10 +100,11 @@ public static class MenuInfo {
* @param price 메뉴 가격
*/
@Builder
- public MenuInfo(long id, @NonNull String name, long price) {
+ public MenuInfo(long id, @NonNull String name, long price, long count) {
this.id = id;
this.name = name;
this.price = price;
+ this.count = count;
options = new ArrayList();
}
@@ -111,15 +149,75 @@ public static class DeliveryInfo {
private long deliveryPrice;
}
+ @Getter
+ @NoArgsConstructor
+ public static class CouponInfo {
+ private long couponIssueId;
+ private long couponId;
+ private String memberId;
+ private String name;
+ private CouponDTO.DiscountType discountType;
+ private long discountValue;
+ private LocalDateTime createdAt;
+ private LocalDateTime endAt;
+
+ /**
+ * 직접 쿠폰 정보를 생설할 경우 사용하는 빌더.
+ * @param couponIssueId 발행 쿠폰 아이디
+ * @param couponId 쿠폰 아이디
+ * @param memberId 회원 아이디
+ * @param name 쿠폰 이름
+ * @param discountType 할인 타입
+ * @param discountValue 할인 가격
+ * @param createAt 발행일
+ * @param endAt 만료일
+ */
+ @Builder
+ public CouponInfo(long couponIssueId, long couponId, String memberId, String name,
+ CouponDTO.DiscountType discountType, long discountValue, LocalDateTime createAt, LocalDateTime endAt) {
+ this.couponIssueId = couponIssueId;
+ this.couponId = couponId;
+ this.memberId = memberId;
+ this.name = name;
+ this.discountType = discountType;
+ this.discountValue = discountValue;
+ this.createdAt = createAt;
+ this.endAt = endAt;
+ }
+ }
+
/**
- * 메뉴 가격, 옵션 가격, 배달 가격을 합친 총 가격을 계산한다.
+ * 메뉴 가격, 옵션 가격, 배달 가격, 할인 가격을 합친 총 가격을 계산한다.
+ * 해당 인스턴스의 내부 상태를 변경시킨다.
* @author jun
* @return
*/
public long totalPrice() {
- return menus.stream().mapToLong(menu -> menu.getPrice()
- + menu.getOptions().stream().mapToLong(option -> option.getPrice()).sum()).sum()
- + deliveryInfo.getDeliveryPrice();
+ long itemsPrice = menus.stream().mapToLong(menu -> {
+ log.debug("메뉴 가격 : {}, 개수 : {}", menu.getPrice(), menu.getCount());
+ return (menu.getPrice()
+ + menu.getOptions().stream().mapToLong(option -> option.getPrice()).sum())
+ * menu.getCount();
+ }).sum();
+
+ long couponDiscountPrice;
+
+ if (couponInfo != null) { // 사용하는 쿠폰이 있을 경우
+ if (couponInfo.getDiscountType() == CouponDTO.DiscountType.PERCENT) {
+ // 이렇게하면 소수점 미만이 버림된다.
+ couponDiscountPrice = itemsPrice * couponInfo.getDiscountValue() / 100L;
+ } else {
+ couponDiscountPrice = couponInfo.getDiscountValue();
+ }
+ } else { // 쿠폰을 사용하지 않을 경우
+ couponDiscountPrice = 0;
+ }
+
+ this.itemsPrice = itemsPrice;
+ this.discountPrice = couponDiscountPrice;
+ this.totalPrice = itemsPrice + deliveryInfo.getDeliveryPrice() - couponDiscountPrice;
+
+ return totalPrice;
}
}
diff --git a/src/main/java/com/delfood/dto/OrderBillDTO.java b/src/main/java/com/delfood/dto/OrderBillDTO.java
index 0783561..9281e07 100644
--- a/src/main/java/com/delfood/dto/OrderBillDTO.java
+++ b/src/main/java/com/delfood/dto/OrderBillDTO.java
@@ -12,6 +12,7 @@ public class OrderBillDTO {
private String memberId;
private OrderStatus orderStatus;
private LocalDateTime startTime;
+ private SimpleCouponInfo couponInfo;
private Long deliveryCost;
private SimpleAddressInfo addressInfo;
private List menus;
@@ -27,4 +28,5 @@ public static class SimpleAddressInfo {
private Integer buildingSideNumber;
private String addressDetail;
}
+
}
diff --git a/src/main/java/com/delfood/dto/OrderDTO.java b/src/main/java/com/delfood/dto/OrderDTO.java
index b3bda8a..f69d64c 100644
--- a/src/main/java/com/delfood/dto/OrderDTO.java
+++ b/src/main/java/com/delfood/dto/OrderDTO.java
@@ -55,7 +55,10 @@ public enum OrderStatus {
@Nullable
private String shopName;
- List items;
+ private List items;
+
+ @Nullable
+ private SimpleCouponInfo couponInfo;
@Builder
public OrderDTO(String memberId, String addressCode, String addressDetail, Long shopId,
diff --git a/src/main/java/com/delfood/dto/ShopDTO.java b/src/main/java/com/delfood/dto/ShopDTO.java
index 4787855..22065a9 100644
--- a/src/main/java/com/delfood/dto/ShopDTO.java
+++ b/src/main/java/com/delfood/dto/ShopDTO.java
@@ -2,6 +2,7 @@
import java.time.LocalDateTime;
import java.util.List;
+import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
@@ -10,6 +11,7 @@
@Getter
@Setter
+@Builder
@EqualsAndHashCode(of = {"id"})
@ToString
public class ShopDTO {
diff --git a/src/main/java/com/delfood/dto/SimpleCouponInfo.java b/src/main/java/com/delfood/dto/SimpleCouponInfo.java
new file mode 100644
index 0000000..7eb49b8
--- /dev/null
+++ b/src/main/java/com/delfood/dto/SimpleCouponInfo.java
@@ -0,0 +1,15 @@
+package com.delfood.dto;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Getter
+@NoArgsConstructor
+public class SimpleCouponInfo {
+ private Long couponIssueId;
+ private Long couponId;
+ private String couponName;
+ private CouponDTO.DiscountType discountType;
+ private Long discountValue;
+ private Long discountPrice;
+}
diff --git a/src/main/java/com/delfood/dto/push/PushMessage.java b/src/main/java/com/delfood/dto/push/PushMessage.java
index 98a00fc..0fcc1db 100644
--- a/src/main/java/com/delfood/dto/push/PushMessage.java
+++ b/src/main/java/com/delfood/dto/push/PushMessage.java
@@ -1,5 +1,6 @@
package com.delfood.dto.push;
+import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import org.joda.time.LocalDateTime;
@@ -11,6 +12,14 @@ public class PushMessage {
@NonNull
private String message;
+ public static final PushMessage ADD_ORDER_REQUEST = new PushMessage("DelFood 주문", "새로운 주문이 들어왔습니다");
+ public static final PushMessage ACCEPT_ORDER_REQUEST = new PushMessage("DelFood 접수", "주문이 접수되었습니다");
+ public static final PushMessage REQUIRED_ORDER_REQUEST = new PushMessage("DelFood 주문취소", "매장에서 주문을 취소하였습니다");
+ public static final PushMessage DELIVERY_MATCH = new PushMessage("DelFood 배달원 매칭", "배달원이 매칭되었습니다");
+ public static final PushMessage DELIVERY_START = new PushMessage("DelFood 배달 시작", "음식 배달이 시작되었습니다");
+ public static final PushMessage DELIVERY_SUCCESS = new PushMessage("DelFood 배달 완료", "배달이 완료되었습니다");
+
+
private LocalDateTime generatedTime;
public PushMessage(String title, String message) {
@@ -18,4 +27,7 @@ public PushMessage(String title, String message) {
this.message = message;
this.generatedTime = LocalDateTime.now();
}
+
+
+
}
diff --git a/src/main/java/com/delfood/dto/rider/RiderDTO.java b/src/main/java/com/delfood/dto/rider/RiderDTO.java
new file mode 100644
index 0000000..3899931
--- /dev/null
+++ b/src/main/java/com/delfood/dto/rider/RiderDTO.java
@@ -0,0 +1,106 @@
+package com.delfood.dto.rider;
+
+import java.time.LocalDateTime;
+import java.util.Objects;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+import org.codehaus.commons.nullanalysis.Nullable;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import com.delfood.utils.SHA256Util;
+
+@Getter
+@NoArgsConstructor
+public class RiderDTO {
+ @NonNull
+ private String id;
+
+ @NonNull
+ private String password;
+
+ @NonNull
+ private String name;
+
+ @NonNull
+ private String tel;
+
+ @NonNull
+ private String mail;
+
+ @Nullable
+ private Status status = Status.DEFAULT;
+
+ @Nullable
+ private LocalDateTime createdAt;
+
+ @Nullable
+ private LocalDateTime updatedAt;
+
+
+ public enum Status {
+ DEFAULT, DELETED
+ }
+
+ /**
+ * RiderDTO Class Builder.
+ * @param id 아이디
+ * @param password 비밀번호
+ * @param name 이름
+ * @param tel 휴대전화 번호
+ * @param mail 메일
+ * @param status 계정 상태
+ * @param createdAt 회원가입일
+ * @param updatedAt 회원정보 수정일
+ */
+ @Builder
+ public RiderDTO(String id, String password, String name, String tel, String mail, Status status,
+ LocalDateTime createdAt, LocalDateTime updatedAt) {
+ this.id = id;
+ this.password = password;
+ this.name = name;
+ this.tel = tel;
+ this.mail = mail;
+ this.status = status == null ? Status.DEFAULT : status;
+ this.createdAt = createdAt == null ? LocalDateTime.now() : createdAt;
+ this.updatedAt = updatedAt == null ? LocalDateTime.now() : updatedAt;
+ }
+
+ /**
+ * null이 허용되지 않는 필드에 null값이 있는지 확인한다.
+ * @author jun
+ * @return
+ */
+ public boolean hasNullData() {
+ return Objects.isNull(this.id)
+ || Objects.isNull(this.password)
+ || Objects.isNull(this.name)
+ || Objects.isNull(this.tel)
+ || Objects.isNull(this.mail);
+ }
+
+ /**
+ * 객체를 복사하여 패스워드를 암호화한 객체를 생성하여 리턴한다.
+ * @author jun
+ * @param riderInfo 암호화할 회원 정보
+ * @return
+ */
+ public static RiderDTO encryptDTO(RiderDTO riderInfo) {
+ String encryptPassword = SHA256Util.encryptSHA256(riderInfo.getPassword());
+ return RiderDTO.builder()
+ .id(riderInfo.getId())
+ .password(encryptPassword)
+ .name(riderInfo.getName())
+ .tel(riderInfo.getTel())
+ .mail(riderInfo.getMail())
+ .status(riderInfo.getStatus())
+ .createdAt(riderInfo.getCreatedAt())
+ .updatedAt(riderInfo.getUpdatedAt())
+ .build();
+ }
+
+ @JsonIgnore
+ public String getPassword() {
+ return this.password;
+ }
+}
diff --git a/src/main/java/com/delfood/error/ErrorController.java b/src/main/java/com/delfood/error/ErrorController.java
index b4aa6c3..2429380 100644
--- a/src/main/java/com/delfood/error/ErrorController.java
+++ b/src/main/java/com/delfood/error/ErrorController.java
@@ -1,7 +1,9 @@
package com.delfood.error;
import com.delfood.error.exception.DuplicateIdException;
+import com.delfood.error.exception.IdDeletedException;
import com.delfood.error.exception.cart.DuplicateItemException;
+import com.delfood.error.exception.coupon.IssuedCouponExistException;
import com.delfood.error.exception.menuGroup.InvalidMenuGroupCountException;
import com.delfood.error.exception.menuGroup.InvalidMenuGroupIdException;
import com.delfood.error.exception.mockPay.MockPayException;
@@ -75,6 +77,12 @@ public ErrorMsg handleCannotShopException(RuntimeException e) {
}
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler(IssuedCouponExistException.class)
+ public ErrorMsg handleIssuedCouponExistException(IssuedCouponExistException e) {
+ return new ErrorMsg(e.getLocalizedMessage(), getSimpleName(e));
+ }
+
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(DuplicateItemException.class)
public ErrorMsg handleDuplicatedItemException(DuplicateItemException e) {
@@ -86,4 +94,10 @@ public ErrorMsg handleDuplicatedItemException(DuplicateItemException e) {
public ErrorMsg handleMockPayException(MockPayException e) {
return new ErrorMsg(e.getLocalizedMessage(), getSimpleName(e));
}
+
+ @ResponseStatus(HttpStatus.UNAUTHORIZED)
+ @ExceptionHandler(IdDeletedException.class)
+ public ErrorMsg handleIdDeletedException(IdDeletedException e) {
+ return new ErrorMsg(e.getLocalizedMessage(), getSimpleName(e));
+ }
}
diff --git a/src/main/java/com/delfood/error/exception/DuplicateException.java b/src/main/java/com/delfood/error/exception/DuplicateException.java
new file mode 100644
index 0000000..902cca2
--- /dev/null
+++ b/src/main/java/com/delfood/error/exception/DuplicateException.java
@@ -0,0 +1,7 @@
+package com.delfood.error.exception;
+
+public class DuplicateException extends RuntimeException{
+ public DuplicateException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/com/delfood/error/exception/IdDeletedException.java b/src/main/java/com/delfood/error/exception/IdDeletedException.java
new file mode 100644
index 0000000..a34248b
--- /dev/null
+++ b/src/main/java/com/delfood/error/exception/IdDeletedException.java
@@ -0,0 +1,7 @@
+package com.delfood.error.exception;
+
+public class IdDeletedException extends IllegalArgumentException {
+ public IdDeletedException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/com/delfood/error/exception/coupon/IssuedCouponExistException.java b/src/main/java/com/delfood/error/exception/coupon/IssuedCouponExistException.java
new file mode 100644
index 0000000..7f3d0d4
--- /dev/null
+++ b/src/main/java/com/delfood/error/exception/coupon/IssuedCouponExistException.java
@@ -0,0 +1,7 @@
+package com.delfood.error.exception.coupon;
+
+public class IssuedCouponExistException extends RuntimeException{
+ public IssuedCouponExistException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/main/java/com/delfood/mapper/CouponIssueMapper.java b/src/main/java/com/delfood/mapper/CouponIssueMapper.java
new file mode 100644
index 0000000..db19ae6
--- /dev/null
+++ b/src/main/java/com/delfood/mapper/CouponIssueMapper.java
@@ -0,0 +1,61 @@
+package com.delfood.mapper;
+
+import java.util.List;
+import org.springframework.stereotype.Repository;
+import com.delfood.dto.CouponIssueDTO;
+import com.delfood.dto.ItemsBillDTO.CouponInfo;
+
+@Repository
+public interface CouponIssueMapper {
+
+ /**
+ * 해당 쿠폰아이디로 발급된 적이 있는 쿠폰의 수를 조회한다.
+ *
+ * @param couponId 쿠폰 아이디
+ * @return 발급된 쿠폰의 수
+ *
+ * @author jinyoung
+ */
+ public int countCouponIssue(Long couponId);
+
+ /**
+ * 회원 아이디와 쿠폰 아이디를 통해 이미 발급된 쿠폰의 수를 조회한다.
+ *
+ * @param memberId 회원 아이디
+ * @param couponId 쿠폰 아이디
+ * @return 발급된 쿠폰의 수
+ *
+ * @author jinyoung
+ */
+ public int countCouponIssueByMemberIdAndCouponId(String memberId, Long couponId);
+
+ /**
+ * 발급 쿠폰을 추가한다.
+ * @param memberId 회원 아이디
+ * @param couponId 쿠폰 아이디
+ * @return
+ *
+ * @author jinyoung
+ */
+ public int insertCouponIssue(String memberId, Long couponId);
+
+ /**
+ * 발급 쿠폰의 상태를 USED로 변경한다.
+ * @param id 발급 쿠폰 아이디
+ * @param paymentId 결제 아이디
+ * @author jinyoung
+ */
+ public int updateCouponIssueStatusToUsed(Long id, Long paymentId);
+
+ /**
+ * 회원이 가진 쿠폰들을 조회한다.
+ * @param memberId 회원 아이디
+ * @return
+ */
+ public List findByMemberId(String memberId);
+
+ public CouponInfo findInfoById(long couponIssueId);
+
+ public CouponIssueDTO findById(long couponIssueId);
+
+}
diff --git a/src/main/java/com/delfood/mapper/CouponMapper.java b/src/main/java/com/delfood/mapper/CouponMapper.java
new file mode 100644
index 0000000..6f99320
--- /dev/null
+++ b/src/main/java/com/delfood/mapper/CouponMapper.java
@@ -0,0 +1,39 @@
+package com.delfood.mapper;
+
+import com.delfood.dto.CouponDTO;
+import java.time.LocalDateTime;
+import java.util.List;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface CouponMapper {
+
+ /**
+ * 쿠폰 추가.
+ * @param couponInfo 쿠폰 정보
+ * @return
+ */
+ public Long insertCoupon(CouponDTO couponInfo);
+
+ /**
+ * 쿠폰 이름과 만료일 수정.
+ * @param id 쿠폰 아이디
+ * @param name 이름
+ * @param endAt 만료일
+ * @return
+ */
+ public int updateCouponNameAndEndAt(Long id, String name, LocalDateTime endAt);
+
+ /**
+ * 쿠폰 삭제.
+ * @param id 쿠폰 아이디
+ * @return
+ */
+ public int deleteCoupon(Long id);
+
+ /**
+ * 만료일이 지나지 않은 쿠폰 조회.
+ * @return
+ */
+ public List findByEndAtGreaterThanNow();
+}
diff --git a/src/main/java/com/delfood/mapper/OrderMapper.java b/src/main/java/com/delfood/mapper/OrderMapper.java
index 5efe3f4..61721a9 100644
--- a/src/main/java/com/delfood/mapper/OrderMapper.java
+++ b/src/main/java/com/delfood/mapper/OrderMapper.java
@@ -1,10 +1,12 @@
package com.delfood.mapper;
import com.delfood.dto.OrderDTO;
+import com.delfood.dto.OrderDTO.OrderStatus;
import com.delfood.dto.OrderItemDTO;
import com.delfood.dto.OrderItemOptionDTO;
import com.delfood.dto.ItemsBillDTO.MenuInfo;
import com.delfood.dto.OrderBillDTO;
+import java.time.LocalDateTime;
import java.util.List;
import lombok.NonNull;
@@ -29,4 +31,14 @@ public interface OrderMapper {
List findByMemberId(String memberId, Long lastViewedOrderId);
boolean isShopItem(List items, Long shopId);
+
+ void updateStatus(@NonNull Long orderId, OrderStatus status);
+
+ List findRequestByOwnerId(String shopId);
+
+ String findOwnerIdByOrderId(Long orderId);
+
+ void updateOrderStatusAndExArrivalTime(Long orderId, LocalDateTime exArrivalTime);
+
+ String findMemberIdByOrderId(Long orderId);
}
diff --git a/src/main/java/com/delfood/mapper/RiderInfoMapper.java b/src/main/java/com/delfood/mapper/RiderInfoMapper.java
new file mode 100644
index 0000000..8df7aea
--- /dev/null
+++ b/src/main/java/com/delfood/mapper/RiderInfoMapper.java
@@ -0,0 +1,24 @@
+package com.delfood.mapper;
+
+import com.delfood.dto.rider.RiderDTO;
+import lombok.NonNull;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface RiderInfoMapper {
+
+ public boolean isExistById(@NonNull String id);
+
+ public void insertRider(@NonNull RiderDTO riderInfo);
+
+ public RiderDTO findByIdAndPassword(@NonNull String id, @NonNull String password);
+
+ public long updatePassword(@NonNull String id, @NonNull String password);
+
+ public long updateStatusAsDeleted(@NonNull String id);
+
+ public boolean isExistAndEffectiveByIdAndPassword(@NonNull String id,
+ @NonNull String password);
+
+ public long updateMail(@NonNull String id, @NonNull String mail);
+}
diff --git a/src/main/java/com/delfood/service/CouponIssueService.java b/src/main/java/com/delfood/service/CouponIssueService.java
new file mode 100644
index 0000000..5dfa4c9
--- /dev/null
+++ b/src/main/java/com/delfood/service/CouponIssueService.java
@@ -0,0 +1,147 @@
+package com.delfood.service;
+
+import java.util.List;
+import java.util.Objects;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.delfood.dto.CouponDTO;
+import com.delfood.dto.CouponIssueDTO;
+import com.delfood.dto.ItemsBillDTO.CouponInfo;
+import com.delfood.error.exception.DuplicateException;
+import com.delfood.mapper.CouponIssueMapper;
+import lombok.extern.log4j.Log4j2;
+
+@Service
+@Log4j2
+public class CouponIssueService {
+
+ @Autowired
+ private CouponIssueMapper couponIssueMapper;
+
+ @Autowired
+ private CouponService couponService;
+
+ /**
+ * 쿠폰이 발급된 적이 있는 지 조회한다.
+ * @param couponId 쿠폰 아이디
+ * @return 쿠폰의 발급여부 ( true : 발급된 적 있음 , false : 발급된 적 없음
+ *
+ * @author jinyoung
+ */
+ public boolean isIssued(Long couponId) {
+ return couponIssueMapper.countCouponIssue(couponId) > 0;
+ }
+
+ /**
+ * 회원이 이미 해당 쿠폰을 발급받은 적이 있는지 체크한다.
+ * @param memberId 회원 아이디
+ * @param couponId 쿠폰 아이디
+ * @return
+ */
+ public boolean checkDuplicateIssue(String memberId, Long couponId) {
+ return couponIssueMapper.countCouponIssueByMemberIdAndCouponId(memberId, couponId) > 0;
+ }
+
+ /**
+ * 회원에게 쿠폰을 발급한다.
+ * @param memberId 회원 아이디
+ * @param couponId 쿠폰 아이디
+ *
+ * @author jinyoung
+ */
+ @Transactional(rollbackFor = RuntimeException.class)
+ public void createCouponIssue(String memberId, Long couponId) {
+
+ if (checkDuplicateIssue(memberId, couponId)) {
+ log.error("coupon has already been issued! memberid :{}, couponId :{}", memberId, couponId);
+ throw new DuplicateException("coupon has already been issued!");
+ }
+
+ int result = couponIssueMapper.insertCouponIssue(memberId, couponId);
+ if (result != 1) {
+ log.error("insert couponIssue Error! memberId : {}, couponId : {}", memberId, couponId);
+ throw new RuntimeException("insert couponIssue Error! ");
+ }
+ }
+
+ /**
+ * 발급 쿠폰 사용.
+ * 발급 쿠폰의 상태를 사용됨으로 변경한다.
+ * @param id 발급 쿠폰 아이디
+ *
+ * @author jinyoung
+ */
+ @Transactional(rollbackFor = RuntimeException.class)
+ public void useCouponIssue(Long id, Long paymentId) {
+ int result = couponIssueMapper.updateCouponIssueStatusToUsed(id, paymentId);
+ if (result != 1) {
+ log.error("update coupon status error! id : {}", id);
+ throw new RuntimeException("update coupon status error!");
+ }
+ }
+
+ /**
+ * 회원이 가진 발행 쿠폰들을 조회한다.
+ * @param memberId 회원 아이디
+ * @return
+ */
+ public List getCouponIssues(String memberId) {
+ return couponIssueMapper.findByMemberId(memberId);
+ }
+
+ /**
+ * 발행 쿠폰 아이디를 기준으로 쿠폰 전반 정보를 조회한다.
+ * @author jun
+ * @param couponIssueId 발행 쿠폰 아이디
+ * @return
+ */
+ public CouponInfo getCouponInfoByIssueId(long couponIssueId) {
+ return couponIssueMapper.findInfoById(couponIssueId);
+ }
+
+
+ /**
+ * 쿠폰으로 인한 할인 가격을 계산한다.
+ * 쿠폰이 퍼센트 쿠폰일 시 입력된 가격을 기준으로 퍼센트 할인 가격을 리턴한다.
+ * 쿠폰이 정액 할인 쿠폰일 시 쿠폰의 할인값을 리턴한다.
+ * 쿠폰의 할인 값이 아이템 가격보다 클 시 아이템의 가격을 할인값으로 리턴한다.
+ *
+ * @author jun
+ * @param couponIssueId
+ * @param price
+ * @return
+ */
+ public long discountPrice(long couponIssueId, long price) {
+ CouponInfo couponInfo = getCouponInfoByIssueId(couponIssueId);
+ long discountPrice = 0;
+
+ if (couponInfo.getDiscountType() == CouponDTO.DiscountType.PERCENT) {
+ discountPrice = price * couponInfo.getDiscountValue() / 100L;
+ } else {
+ discountPrice = couponInfo.getDiscountValue();
+ }
+
+ return discountPrice > price ? price : discountPrice;
+ }
+
+ /**
+ * 해당 발행 쿠폰이 사용상태인지 확인한다. 사용한 쿠폰이라면 true를 반환한다.
+ * @author jun
+ * @param couponIssueId 발행 쿠폰 아이디
+ * @return
+ */
+ public boolean isUsed(long couponIssueId) {
+ CouponIssueDTO couponIssueInfo = couponIssueMapper.findById(couponIssueId);
+
+ if (Objects.isNull(couponIssueInfo)) {
+ log.error("발행쿠폰 사용여부 체크 오류! 조회한 발행 쿠폰 정보가 없습니다. 발행 쿠폰 아이디 : {}", couponIssueId);
+ throw new IllegalArgumentException("잘못된 쿠폰 발행 번호입니다.");
+ }
+
+ return couponIssueInfo.getStatus().equals(CouponIssueDTO.Status.USED);
+ }
+
+
+
+}
diff --git a/src/main/java/com/delfood/service/CouponService.java b/src/main/java/com/delfood/service/CouponService.java
new file mode 100644
index 0000000..fc7e8b5
--- /dev/null
+++ b/src/main/java/com/delfood/service/CouponService.java
@@ -0,0 +1,119 @@
+package com.delfood.service;
+
+import com.delfood.dto.CouponDTO;
+import com.delfood.dto.CouponDTO.DiscountType;
+import com.delfood.error.exception.coupon.IssuedCouponExistException;
+import com.delfood.mapper.CouponMapper;
+import java.time.LocalDateTime;
+import java.util.List;
+import lombok.extern.log4j.Log4j2;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Log4j2
+public class CouponService {
+
+ @Autowired
+ private CouponMapper couponMapper;
+
+ @Autowired
+ private CouponIssueService couponIssueService;
+
+ /**
+ * 쿠폰 추가.
+ * @param couponInfo
+ *
+ * @author jinyoung
+ */
+ @Transactional(rollbackFor = RuntimeException.class)
+ public void addCoupon(CouponDTO couponInfo) {
+
+ verifyDiscountData(couponInfo.getDiscountType(), couponInfo.getDiscountValue());
+
+ Long insertResult = couponMapper.insertCoupon(couponInfo);
+
+ if (insertResult != 1) {
+ log.error("coupon Insert Error! {}", couponInfo.toString());
+ throw new RuntimeException("coupon Insert Error");
+ }
+
+ if (couponInfo.getEndAt().isBefore(couponInfo.getCreatedAt())) {
+ log.error("coupon expiration date is ealire than creation date! "
+ + "EndAt : {}, startAt : {}",couponInfo.getEndAt(), couponInfo.getCreatedAt());
+ throw new IllegalStateException("coupon expiration date is ealire than creation date!");
+ }
+
+ }
+
+ /**
+ * 쿠폰 할인 값 검증.
+ * @param discountType 할인 타입
+ * @param discountValue 할인 값
+ * @throws IllegalArgumentException
+ *
+ * @author jinyoung
+ */
+ public static void verifyDiscountData(DiscountType discountType, Long discountValue) {
+ if (DiscountType.PERCENT == discountType
+ && ((discountValue < 0 || discountValue > 100))) {
+ log.error("coupon discount setting error! couponType : {} , discountValue : {}",
+ discountType, discountValue);
+ throw new IllegalArgumentException("coupon discount setting error!");
+ }
+ }
+
+ /**
+ * 쿠폰 이름과 만료일 수정.
+ *
+ * @param id 쿠폰 아이디
+ * @param name 이름
+ * @param endAt 만료일
+ *
+ * @author jinyoung
+ */
+ @Transactional(rollbackFor = RuntimeException.class)
+ public void updateCouponNameAndEndAt(Long id, String name, LocalDateTime endAt) {
+ if (couponIssueService.isIssued(id)) {
+ log.error("Issued Coupon already exists");
+ throw new IssuedCouponExistException("Issued Coupon already exists");
+ }
+
+ int result = couponMapper.updateCouponNameAndEndAt(id, name, endAt);
+ if (result != 1) {
+ log.error("coupon update error! id : {}, name : {}, EndAt : {} ", id, name, endAt);
+ throw new RuntimeException("coupon update error!");
+ }
+ }
+
+ /**
+ * 쿠폰삭제.
+ * @param id 쿠폰 아이디
+ *
+ * @author jinyoung
+ */
+ @Transactional(rollbackFor = RuntimeException.class)
+ public void deleteCoupon(Long id) {
+ if (couponIssueService.isIssued(id)) {
+ log.error("Issued Coupon already exists");
+ throw new IssuedCouponExistException("Issued Coupon already exists");
+ }
+
+ int result = couponMapper.deleteCoupon(id);
+ if (result != 1) {
+ log.error("coupon delete error! id : {}",id);
+ throw new RuntimeException("coupon delete error!");
+ }
+ }
+
+ /**
+ * 사용 가능한 쿠폰을 조회한다. (만료일이 현재시간 이후의 쿠폰만 조회)
+ * @return 쿠폰 리스트
+ */
+ public List getAvaliableCoupons() {
+ return couponMapper.findByEndAtGreaterThanNow();
+ }
+
+}
diff --git a/src/main/java/com/delfood/service/OrderService.java b/src/main/java/com/delfood/service/OrderService.java
index 932a8f3..b6184c0 100644
--- a/src/main/java/com/delfood/service/OrderService.java
+++ b/src/main/java/com/delfood/service/OrderService.java
@@ -3,30 +3,27 @@
import com.delfood.controller.response.OrderResponse;
import com.delfood.dto.AddressDTO;
import com.delfood.dto.ItemsBillDTO;
-import com.delfood.dto.ItemsBillDTO.MenuInfo;
import com.delfood.dto.ItemsBillDTO.ShopInfo;
-import com.delfood.dto.ItemsBillDTO.MenuInfo.OptionInfo;
-import com.delfood.dto.MemberDTO.Status;
-import com.delfood.error.exception.order.TotalPriceMismatchException;
import com.delfood.dto.MemberDTO;
-import com.delfood.dto.MenuDTO;
-import com.delfood.dto.OptionDTO;
+import com.delfood.dto.OrderBillDTO;
import com.delfood.dto.OrderDTO;
import com.delfood.dto.OrderItemDTO;
import com.delfood.dto.OrderItemOptionDTO;
import com.delfood.dto.PaymentDTO;
import com.delfood.dto.PaymentDTO.Type;
-import com.delfood.dto.OrderBillDTO;
-import com.delfood.mapper.OptionMapper;
+import com.delfood.dto.push.PushMessage;
import com.delfood.mapper.OrderMapper;
import com.delfood.utils.OrderUtil;
-import lombok.NonNull;
-import lombok.extern.log4j.Log4j2;
+import com.google.firebase.database.annotations.Nullable;
+import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
+import java.util.Objects;
+import lombok.NonNull;
+import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
@@ -50,8 +47,13 @@ public class OrderService {
@Autowired
private PaymentService paymentService;
+ @Autowired
+ private PushService pushService;
+
+ @Autowired
+ private CouponIssueService couponIssueService;
+
/**
- * 미완성 로직
* 주문 요청을 진행한다.
* 사용자가 주문 요청시 전달받은 가격과, 서버에서 직접 비교한 가격을 비교하여 다르면 예외처리 할 예정.
* @param memberId 고객 아이디
@@ -59,13 +61,15 @@ public class OrderService {
* @return
*/
@Transactional
- public OrderResponse order(String memberId, List items, long shopId) {
-
+ public OrderResponse order(String memberId, List items, long shopId,
+ @Nullable Long couponIssueId) {
+
// 주문 준비 작업. 결제 전.
- Long orderId = preOrder(memberId, items, shopId);
+ Long orderId = doOrder(memberId, items, shopId);
// 계산서 발행
- ItemsBillDTO bill = getBill(memberId, items);
+ ItemsBillDTO bill = getBill(memberId, items, couponIssueId);
+
// 가상 결제 진행
PaymentDTO paymentInfo = PaymentDTO.builder()
@@ -78,8 +82,19 @@ public OrderResponse order(String memberId, List items, long shopI
PaymentDTO payResult = mockPayService.pay(paymentInfo);
paymentService.insertPayment(payResult);
- // 사장님에게 알림(푸시)
+ // 결제 완료 처리
+ updateStatus(orderId, OrderDTO.OrderStatus.ORDER_REQUEST);
+
+ // 쿠폰 사용처리
+ if (bill.getCouponInfo() != null) {
+ couponIssueService.useCouponIssue(bill.getCouponInfo().getCouponIssueId(), payResult.getId());
+ }
+
+ // 사장님에게 알림(푸시)
+ PushMessage pushMsg = PushMessage.ADD_ORDER_REQUEST;
+ String ownerId = shopService.getShop(shopId).getOwnerId();
+ pushService.sendMessageToOwner(pushMsg, ownerId); // Exception이 발생하지 않는다.
return new OrderResponse(bill, orderId);
}
@@ -87,13 +102,14 @@ public OrderResponse order(String memberId, List items, long shopI
/**
* 주문 테이블에 insert를 진행한다.
* 주문 메뉴, 주문 옵션이 추가된다.
+ * 주문도중 에러가 나더라도 주문기록을 남기기 위해 독자적인 트랜잭션을 가진다.
*
* @param memberId 고객 아이디
* @param items 주문할 아이템들
* @return
*/
- @Transactional
- private Long preOrder(String memberId, List items, Long shopId) {
+ @Transactional(propagation = Propagation.NESTED)
+ private Long doOrder(String memberId, List items, Long shopId) {
MemberDTO memberInfo = memberService.getMemberInfo(memberId);
OrderDTO order = OrderDTO
.builder()
@@ -139,11 +155,18 @@ private Long preOrder(String memberId, List items, Long shopId) {
* @return
*/
@Transactional(readOnly = true)
- public ItemsBillDTO getBill(String memberId, List items) {
+ public ItemsBillDTO getBill(String memberId, List items, Long couponIssueId) {
// 고객 주소 정보 추출
AddressDTO addressInfo = memberService.getMemberInfo(memberId).getAddressInfo();
// 매장 정보 추출
ShopInfo shopInfo = shopService.getShopByMenuId(items.get(0).getMenuId());
+
+ // 쿠폰 정보 추출
+ ItemsBillDTO.CouponInfo couponInfo = null;
+ if (couponIssueId != null) {
+ couponInfo = couponIssueService.getCouponInfoByIssueId(couponIssueId);
+ }
+
// 배달료 계산
long deliveryPrice = addressService.deliveryPrice(memberId, shopInfo.getId());
@@ -154,13 +177,15 @@ public ItemsBillDTO getBill(String memberId, List items) {
.shopInfo(shopInfo)
.deliveryPrice(deliveryPrice)
.menus(orderMapper.findItemsBill(items))
+ .couponInfo(couponInfo)
+ .ordersItems(items)
.build();
return bill;
}
/**
- * 총 가격을 계산한다.
+ * 아이템들의 총 가격을 계산한다.
* @author jun
* @param items 계산할 아이템들
* @return 총 가격
@@ -168,10 +193,7 @@ public ItemsBillDTO getBill(String memberId, List items) {
@Transactional(readOnly = true)
public long totalPrice(String memberId, List items) {
long totalPrice = orderMapper.findItemsPrice(items);
- long deliveryPrice = addressService.deliveryPrice(memberId,
- shopService.getShopByMenuId(items.get(0).getMenuId()).getId());
-
- return totalPrice + deliveryPrice;
+ return totalPrice;
}
@@ -209,7 +231,6 @@ public List getMemberOrder(String memberId, Long lastViewedOrderId) {
* 주문 번호를 기반으로 주문 상세를 조회한다.
* @author jun
* @param orderId 주문 아이디
- * @param memberId 고객 아이디
* @return
*/
public OrderDTO getOrder(Long orderId) {
@@ -227,5 +248,49 @@ public OrderDTO getOrder(Long orderId) {
public boolean isShopItems(List items, Long shopId) {
return orderMapper.isShopItem(items, shopId);
}
+
+ /**
+ * 주문 상태를 변경시킨다.
+ * @author jun
+ * @param orderId 주문 아이디
+ * @param status 변경시킬 주문 상태
+ */
+ public void updateStatus(@NonNull Long orderId, OrderDTO.OrderStatus status) {
+ orderMapper.updateStatus(orderId, status);
+ }
+
+ /**
+ * 사장님 아이디를 기반으로 주문 정보를 조회한다.
+ * @param ownerId 사장님 아이디
+ * @return
+ */
+ public List getOwnerOrderRequest(String ownerId) {
+ return orderMapper.findRequestByOwnerId(ownerId);
+ }
+
+ public boolean isOwnerOrder(String ownerId, Long orderId) {
+ String ownerIdByOrderId = orderMapper.findOwnerIdByOrderId(orderId);
+ return Objects.equals(ownerId, ownerIdByOrderId);
+ }
+
+ /**
+ * 해당 주문을 승인하고 도착 예정시간을 설정한다.
+ * 승인 완료 후 고객에게 푸시 메세지를 전송한다.
+ * @author jun
+ * @param orderId 주문 아이디
+ * @param minute 배달까지 몇 분 걸릴지 예상시간
+ */
+ @Transactional
+ public void orderApprove(Long orderId, long minute) {
+
+ LocalDateTime exArrivalTime = LocalDateTime.now().plusMinutes(minute);
+ orderMapper.updateOrderStatusAndExArrivalTime(orderId, exArrivalTime);
+ String memberId = orderMapper.findMemberIdByOrderId(orderId);
+
+ // 푸시메세지 전송
+ PushMessage messageInfo = new PushMessage("DelFood 주문 승인",
+ "사장님이 주문을 승인했어요! 도착 예정 시간 " + minute + "분 후");
+ pushService.sendMessageToMember(messageInfo, memberId);
+ }
}
diff --git a/src/main/java/com/delfood/service/OwnerService.java b/src/main/java/com/delfood/service/OwnerService.java
index 79bbf20..265f477 100644
--- a/src/main/java/com/delfood/service/OwnerService.java
+++ b/src/main/java/com/delfood/service/OwnerService.java
@@ -1,17 +1,15 @@
package com.delfood.service;
import com.delfood.dto.OwnerDTO;
+import com.delfood.error.exception.DuplicateException;
import com.delfood.error.exception.DuplicateIdException;
import com.delfood.mapper.OwnerMapper;
import com.delfood.utils.SHA256Util;
import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cache.annotation.Cacheable;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.client.HttpStatusCodeException;
@Service
@@ -86,8 +84,9 @@ public OwnerDTO getOwner(String id) {
@Transactional(rollbackFor = RuntimeException.class)
public void updateOwnerMailAndTel(String id, String password, String mail, String tel) {
// 정보 변경시 패스워드를 입력받는다. 해당 패스워드가 틀릴 시 정보는 변경되지 않는다.
- if (ownerMapper.findByIdAndPassword(id, password) == null) {
- throw new IllegalArgumentException("패스워드가 일치하지 않습니다");
+ if (ownerMapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(password)) == null) {
+ log.error("password does not match");
+ throw new IllegalArgumentException("password does not match");
}
int result = ownerMapper.updateMailAndTel(id, mail, tel);
@@ -101,20 +100,26 @@ public void updateOwnerMailAndTel(String id, String password, String mail, Strin
* 사장 비밀번호 수정.
*
* @param id 아이디
- * @param passwordAfterChange 변경할 비밀번호
+ * @param beforePassword 변경전 비밀번호
+ * @param afterPassword 변경할 비밀번호
* @return
*/
@Transactional(rollbackFor = RuntimeException.class) // runtimeException이 발생하면 rollback을 수행한다.
- public void updateOwnerPassword(String id, String passwordBeforeChange, String passwordAfterChange) {
- if (ownerMapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(passwordBeforeChange)) == null) { // 아이디와 비밀번호 불일치
- throw new IllegalArgumentException();
- } else if (passwordBeforeChange.equals(SHA256Util.encryptSHA256(passwordAfterChange))) { // 이전 패스워드와 동일한 경우
- throw new HttpStatusCodeException(HttpStatus.CONFLICT, "변경 전 패스워드와 중복됩니다") {};
+ public void updateOwnerPassword(String id, String beforePassword, String afterPassword) {
+
+ if (ownerMapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(beforePassword))
+ == null) {
+ log.error("id and password do not match id : {}, password : {}",id,beforePassword);
+ throw new IllegalArgumentException("id and password do not match");
+ } else if (StringUtils.equals(beforePassword, afterPassword)) {
+ log.error("password duplication before: {}, after : {}",
+ beforePassword, afterPassword);
+ throw new DuplicateException("password duplication");
}
- String cryptoPassword = SHA256Util.encryptSHA256(passwordAfterChange);
+ String cryptoPassword = SHA256Util.encryptSHA256(afterPassword);
int result = ownerMapper.updatePassword(id, cryptoPassword);
if (result != 1) {
- log.error("updateOwnerPassword ERROR! id : {}, password : {}", id, passwordAfterChange);
+ log.error("updateOwnerPassword ERROR! id : {}, password : {}", id, afterPassword);
throw new RuntimeException("password update error");
}
diff --git a/src/main/java/com/delfood/service/PushService.java b/src/main/java/com/delfood/service/PushService.java
index fa17efe..0c169a8 100644
--- a/src/main/java/com/delfood/service/PushService.java
+++ b/src/main/java/com/delfood/service/PushService.java
@@ -71,6 +71,7 @@ public void init() {
* @author jun
* @param messageInfo 전송할 푸시 정보
*/
+ @Async("asyncTask")
public void sendByToken(PushMessageForOne messageInfo) {
Message message = Message.builder()
.setToken(messageInfo.getToken())
@@ -84,7 +85,7 @@ public void sendByToken(PushMessageForOne messageInfo) {
response = FirebaseMessaging.getInstance().send(message);
log.info("Sent message: " + response);
} catch (FirebaseMessagingException e) {
- throw new RuntimeException(e.getMessage());
+ log.error("cannot send message by token. error info : {}", e.getMessage());
}
}
@@ -106,7 +107,7 @@ public void sendByTopic(PushMessageForTopic topicMessageInfo) {
response = FirebaseMessaging.getInstance().send(message);
log.info("Sent message: " + response);
} catch (FirebaseMessagingException e) {
- throw new RuntimeException(e.getMessage());
+ log.error("cannot send message by topic. error info : {}", e.getMessage());
}
}
@@ -118,6 +119,12 @@ public void sendByTopic(PushMessageForTopic topicMessageInfo) {
@Async("asyncTask")
public void sendMessageToMember(PushMessage messageInfo, String memberId) {
List tokens = fcmDao.getMemberTokens(memberId);
+
+ if (tokens.size() == 0) { // 토큰 개수가 0개이면 오류가 발생한다.
+ log.debug("해당 회원의 FCM 토큰이 없습니다. 회원 아이디 : {}, 메세지 정보 : {}", memberId, messageInfo);
+ return;
+ }
+
List messages = tokens.stream().map(token -> Message.builder()
.putData("title", messageInfo.getTitle())
.putData("message", messageInfo.getMessage())
@@ -130,7 +137,8 @@ public void sendMessageToMember(PushMessage messageInfo, String memberId) {
response = FirebaseMessaging.getInstance().sendAll(messages);
log.info("Sent message: " + response);
} catch (FirebaseMessagingException e) {
- throw new RuntimeException(e.getMessage());
+ log.error("cannot send to member push message. error info : {}", e.getMessage());
+ addErrorMemberPush(memberId, messages);
}
}
@@ -142,6 +150,12 @@ public void sendMessageToMember(PushMessage messageInfo, String memberId) {
@Async("asyncTask")
public void sendMessageToOwner(PushMessage messageInfo, String ownerId) {
List tokens = fcmDao.getOwnerTokens(ownerId);
+
+ if (tokens.size() == 0) {
+ log.debug("해당 사장님의 FCM 토큰이 없습니다. 회원 아이디 : {}, 메세지 정보 : {}", ownerId, messageInfo);
+ return;
+ }
+
List messages = tokens.stream().map(token -> Message.builder()
.putData("title", messageInfo.getTitle())
.putData("message", messageInfo.getMessage())
@@ -154,7 +168,8 @@ public void sendMessageToOwner(PushMessage messageInfo, String ownerId) {
response = FirebaseMessaging.getInstance().sendAll(messages);
log.info("Sent message: " + response);
} catch (FirebaseMessagingException e) {
- throw new RuntimeException(e.getMessage());
+ log.error("cannot send message to owner. error info : {}", e.getMessage());
+ addErrorOwnerPush(ownerId, messages);
}
}
@@ -199,4 +214,12 @@ public List getMemberTokens(String memberId) {
public List getOwnerTokens(String ownerId) {
return fcmDao.getOwnerTokens(ownerId);
}
+
+ public void addErrorMemberPush(String memberId, List messages) {
+ fcmDao.addMemberErrorPush(memberId, messages);
+ }
+
+ public void addErrorOwnerPush(String ownerId, List messages) {
+ fcmDao.addMemberErrorPush(ownerId, messages);
+ }
}
diff --git a/src/main/java/com/delfood/service/rider/RiderInfoService.java b/src/main/java/com/delfood/service/rider/RiderInfoService.java
new file mode 100644
index 0000000..7478520
--- /dev/null
+++ b/src/main/java/com/delfood/service/rider/RiderInfoService.java
@@ -0,0 +1,147 @@
+package com.delfood.service.rider;
+
+import com.delfood.dto.rider.RiderDTO;
+import com.delfood.error.exception.DuplicateException;
+import com.delfood.error.exception.IdDeletedException;
+import com.delfood.mapper.RiderInfoMapper;
+import com.delfood.utils.SHA256Util;
+import java.util.Objects;
+import lombok.NonNull;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Log4j2
+public class RiderInfoService {
+
+ @Autowired
+ private RiderInfoMapper riderInfoMapper;
+
+ private static final IllegalArgumentException passwordMismatchException =
+ new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
+
+ /**
+ * 해당 아이디가 중복된 아이디인지 확인한다.
+ *
+ * @author jun
+ * @param riderId 중복인지 검사할 아이디
+ * @return
+ */
+ public boolean isDuplicatedId(@NonNull String riderId) {
+ return riderInfoMapper.isExistById(riderId);
+ }
+
+ /**
+ * 라이더 회원가입을 진행한다.
+ * @param riderInfo 회원 가입 정보
+ */
+ @Transactional
+ public void signUp(@NonNull RiderDTO riderInfo) {
+ if (isDuplicatedId(riderInfo.getId())) {
+ throw new DuplicateException("아이디 \"" + riderInfo.getId() + "\" 는 이미 가입한 아이디입니다.");
+ }
+
+ riderInfoMapper.insertRider(riderInfo);
+ }
+
+ /**
+ * 라이더 로그인을 진행한다.
+ * @param id 아이디
+ * @param password 암호화 전 비밀번호
+ * @return
+ */
+ public RiderDTO signIn(@NonNull String id, @NonNull String password) {
+ String encryptedPassword = SHA256Util.encryptSHA256(password);
+ RiderDTO riderInfo = getRiderInfo(id, encryptedPassword);
+
+ if (RiderDTO.Status.DELETED.equals(riderInfo.getStatus())) {
+ log.info("signIn - 삭제 회원 로그인 시도. id : {}, password : {}", id, encryptedPassword);
+ throw new IdDeletedException("Rider의 계정이 삭제 상태입니다. 로그인할 수 없습니다.");
+ }
+
+
+
+ return riderInfo;
+ }
+
+ /**
+ * 라이더의 비밀번호를 변경한다.
+ * @param id 라이더 아이디
+ * @param passwordBeforeChange 변경 전 비밀번호
+ * @param passwordAfterChange 변경할 비밀번호
+ */
+ @Transactional
+ public void changePassword(@NonNull String id, @NonNull String passwordBeforeChange,
+ String passwordAfterChange) {
+ if (isEffective(id, passwordBeforeChange) == false) {
+ throw passwordMismatchException;
+ }
+
+ String encryptedPasswordAfter = SHA256Util.encryptSHA256(passwordAfterChange);
+ riderInfoMapper.updatePassword(id, encryptedPasswordAfter);
+ }
+
+ /**
+ * 라이더 계정 정보를 조회한다.
+ * 일치하는 계정이 없을 시 예외를 발생시킨다.
+ * @author jun
+ * @param id 조회할 라이더 계정 아이디
+ * @param encryptedPassword 암호화를 진행한 비밀번호
+ * @return
+ */
+ public RiderDTO getRiderInfo(@NonNull String id, @NonNull String encryptedPassword) {
+ RiderDTO riderInfo = riderInfoMapper.findByIdAndPassword(id, encryptedPassword);
+
+ if (Objects.isNull(riderInfo)) {
+ log.info("회원 정보 없음. id : {}, password : {}", id, encryptedPassword);
+ throw new IllegalArgumentException("id 또는 password가 일치하는 회원 정보가 없습니다.");
+ }
+
+ return riderInfo;
+ }
+
+ /**
+ * 라이더 계정을 삭제상태로 만든다.
+ * @param id 삭제할 라이더 아이디
+ * @param password 삭제하기 전 유효성 검사를 위한 비밀번호
+ */
+ @Transactional
+ public void deleteAccount(@NonNull String id, @NonNull String password) {
+ if (isEffective(id, password) == false) {
+ log.info("회원 삭제를 시도하였지만 실패하였습니다. 원인 : 비밀번호 불일치. id : {}", id);
+ throw passwordMismatchException;
+ }
+
+ riderInfoMapper.updateStatusAsDeleted(id);
+ }
+
+ /**
+ * 아이디와 비밀번호를 기반으로 유효한 아이디인지, 아이디와 비밀번호가 일치하는지 검사한다.
+ * @author jun
+ * @param id 검사할 아이디
+ * @param password 검사할 비밀번ㄹ호
+ * @return
+ */
+ public boolean isEffective(@NonNull String id, @NonNull String password) {
+ String encryptedPassword = SHA256Util.encryptSHA256(password);
+ return riderInfoMapper.isExistAndEffectiveByIdAndPassword(id, encryptedPassword);
+ }
+
+ /**
+ * 라이더의 메일 주소를 변경한다.
+ * @author jun
+ * @param id 메일을 변경할 아이디
+ * @param password 유효성 검사를 위한 비밀번호
+ * @param mail 변경할 메일 주소
+ */
+ @Transactional
+ public void changeMail(@NonNull String id, @NonNull String password, @NonNull String mail) {
+ if (isEffective(id, password) == false) {
+ throw passwordMismatchException;
+ }
+
+ riderInfoMapper.updateMail(id, mail);
+ }
+}
diff --git a/src/main/java/com/delfood/utils/RedisKeyFactory.java b/src/main/java/com/delfood/utils/RedisKeyFactory.java
index b18e381..cbfa42d 100644
--- a/src/main/java/com/delfood/utils/RedisKeyFactory.java
+++ b/src/main/java/com/delfood/utils/RedisKeyFactory.java
@@ -2,7 +2,7 @@
public class RedisKeyFactory {
public enum Key {
- CART, FCM_MEMBER, FCM_OWNER
+ CART, FCM_MEMBER, FCM_OWNER, FCM_MEMBER_ERROR, FCM_OWNER_ERROR
}
// 인스턴스화 방지
@@ -33,4 +33,12 @@ public static String generateFcmOwnerKey(String ownerId) {
public static String getIdFromKey(String key) {
return key.substring(0, key.indexOf(":"));
}
+
+ public static String generateFcmMemberErrorKey(String memberId) {
+ return generateKey(memberId, Key.FCM_MEMBER_ERROR);
+ }
+
+ public static String generateFcmOwnerErrorKey(String ownerId) {
+ return generateKey(ownerId, Key.FCM_OWNER_ERROR);
+ }
}
diff --git a/src/main/java/com/delfood/utils/SessionUtil.java b/src/main/java/com/delfood/utils/SessionUtil.java
index a689943..02e57a4 100644
--- a/src/main/java/com/delfood/utils/SessionUtil.java
+++ b/src/main/java/com/delfood/utils/SessionUtil.java
@@ -1,11 +1,13 @@
package com.delfood.utils;
import javax.servlet.http.HttpSession;
+import lombok.NonNull;
public class SessionUtil {
private static final String LOGIN_MEMBER_ID = "LOGIN_MEMBER_ID";
private static final String LOGIN_OWNER_ID = "LOGIN_OWNER_ID";
+ private static final String LOGIN_RIDER_ID = "LOGIN_RIDER_ID";
// 인스턴스화 방지
private SessionUtil() {}
@@ -81,6 +83,24 @@ public static void logoutMember(HttpSession session) {
public static void logoutOwner(HttpSession session) {
session.removeAttribute(LOGIN_OWNER_ID);
}
+
+ /**
+ * 로그인한 라이더의 id를 세션에 저장한다.
+ * @author jun
+ * @param session 사용자의 세션
+ * @param id 저장할 라이더 아이디
+ */
+ public static void setLoginRiderId(HttpSession session, @NonNull String id) {
+ session.setAttribute(LOGIN_RIDER_ID, id);
+ }
+
+ public static String getLoginRiderId(HttpSession session) {
+ return (String) session.getAttribute(LOGIN_RIDER_ID);
+ }
+
+ public static void logoutRider(HttpSession session) {
+ session.removeAttribute(LOGIN_RIDER_ID);
+ }
diff --git a/src/main/resources/mybatis/mapper/coupon.xml b/src/main/resources/mybatis/mapper/coupon.xml
new file mode 100644
index 0000000..2374059
--- /dev/null
+++ b/src/main/resources/mybatis/mapper/coupon.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+ INSERT INTO COUPON(name, discount_type, discount_value, end_at)
+ VALUES(#{name}, #{discountType}, #{discountValue}, #{endAt})
+
+ SELECT created_at FROM COUPON
+ WHERE id = (SELECT LAST_INSERT_ID())
+
+
+
+
+ UPDATE COUPON
+ SET name = #{name}
+ AND end_at = #{endAt}
+ WHERE id = #{id}
+
+
+
+ UPDATE COUPON
+ SET status = "DELETED"
+ WHERE id = #{id}
+
+
+
+
+
diff --git a/src/main/resources/mybatis/mapper/couponIssue.xml b/src/main/resources/mybatis/mapper/couponIssue.xml
new file mode 100644
index 0000000..b30c249
--- /dev/null
+++ b/src/main/resources/mybatis/mapper/couponIssue.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+ INSERT INTO COUPON_ISSUE(member_id, coupon_id)
+ VALUES(#{memberId}, #{couponId})
+
+
+
+ UPDATE COUPON_ISSUE
+ SET status = 'USED',
+ payment_id = #{paymentId}
+ WHERE id = #{id}
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/mybatis/mapper/orders.xml b/src/main/resources/mybatis/mapper/orders.xml
index 927c99f..216b253 100644
--- a/src/main/resources/mybatis/mapper/orders.xml
+++ b/src/main/resources/mybatis/mapper/orders.xml
@@ -14,6 +14,14 @@
+
+
+
+
+
+
+
+
@@ -30,6 +38,7 @@
+
@@ -133,13 +151,22 @@
item_opt.id itemOptionId,
opt.id optionId,
opt.name optionName,
- opt.price optionPrice
+ opt.price optionPrice,
+ cpn_isu.id couponIssueId,
+ cpn.id couponId,
+ cpn.name couponName,
+ cpn.discount_type discountType,
+ cpn.discount_value discountValue,
+ pay.amount_discount discountPrice
FROM ORDERS odr LEFT OUTER JOIN ORDERS_ITEM item ON (odr.id = item.order_id)
LEFT OUTER JOIN ORDERS_ITEM_OPTION item_opt ON (item.id = item_opt.order_item_id)
INNER JOIN MENU menu ON (menu.id = item.menu_id)
LEFT OUTER JOIN OPTION opt ON (opt.menu_id = menu.id)
INNER JOIN SHOP shop ON (odr.shop_id = shop.id)
INNER JOIN MEMBER member ON (odr.member_id = member.id)
+ INNER JOIN PAYMENT pay ON (pay.order_id = odr.id)
+ LEFT OUTER JOIN COUPON_ISSUE cpn_isu ON (pay.id = cpn_isu.payment_id)
+ LEFT OUTER JOIN COUPON cpn ON (cpn_isu.coupon_id = cpn.id)
WHERE member.id = #{memberId}
AND odr.id > #{lastViewedOrderId}
@@ -164,6 +191,14 @@
+
+
+
+
+
+
+
+
@@ -178,7 +213,7 @@
@@ -257,4 +301,73 @@
#{option.optionId}
)
+
+
+
+ UPDATE ORDERS
+ SET order_status = #{status}
+ WHERE id = #{orderId}
+
+
+
+
+
+
+
+ UPDATE ORDERS
+ SET order_status = 'ORDER_APPROVAL',
+ ex_arrival_time = #{exArrivalTime}
+ WHERE id = #{orderId}
+
+
+
+
diff --git a/src/main/resources/mybatis/mapper/payment.xml b/src/main/resources/mybatis/mapper/payment.xml
index 0db374a..230a4f0 100644
--- a/src/main/resources/mybatis/mapper/payment.xml
+++ b/src/main/resources/mybatis/mapper/payment.xml
@@ -1,7 +1,7 @@
-
+
INSERT INTO PAYMENT
(type, amount_payment, pay_time, order_id, status, amount_discount)
VALUES
diff --git a/src/main/resources/mybatis/mapper/rider.xml b/src/main/resources/mybatis/mapper/rider.xml
new file mode 100644
index 0000000..7b54cf9
--- /dev/null
+++ b/src/main/resources/mybatis/mapper/rider.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+ INSERT INTO RIDER(id, password, name, tel, mail)
+ VALUES (#{id}, #{password}, #{name}, #{tel}, #{mail})
+
+
+
+
+
+ UPDATE RIDER
+ SET password = #{password},
+ updated_at = NOW()
+ WHERE id = #{id}
+
+
+
+ UPDATE RIDER
+ SET status = 'DELETED',
+ updated_at = NOW()
+ WHERE id = #{id}
+
+
+
+
+
+ UPDATE RIDER
+ SET mail = #{mail},
+ updated_at = NOW()
+ WHERE id = #{id}
+
+
\ No newline at end of file
diff --git a/src/test/java/com/delfood/service/AddressServiceTest.java b/src/test/java/com/delfood/service/AddressServiceTest.java
new file mode 100644
index 0000000..96f830b
--- /dev/null
+++ b/src/test/java/com/delfood/service/AddressServiceTest.java
@@ -0,0 +1,164 @@
+package com.delfood.service;
+
+import static org.junit.Assert.assertThat;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.mockito.BDDMockito.given;
+
+import com.delfood.controller.reqeust.GetAddressByZipRequest;
+import com.delfood.controller.reqeust.GetAddressesByRoadRequest;
+import com.delfood.dto.AddressDTO;
+import com.delfood.dto.address.Position;
+import com.delfood.mapper.AddressMapper;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AddressServiceTest {
+
+ @InjectMocks
+ AddressService addressService;
+
+ @Mock
+ AddressMapper addressMapper;
+
+ public AddressDTO generateAddressDTO() {
+ AddressDTO addressInfo = new AddressDTO();
+ addressInfo.setAdministrativeTownCode("1111051500");
+ addressInfo.setAdministrativeTownName("청운효자동");
+ addressInfo.setBuildingCenterPointXCoordinate(953035.318387);
+ addressInfo.setBuildingCenterPointYCoordinate(1954819.846972);
+ addressInfo.setBuildingCount(9);
+ addressInfo.setBuildingManagementNumber("1111010100100010000030843");
+ addressInfo.setBuildingNameChangeHistory("");
+ addressInfo.setBuildingNameForCity("청운벽산빌리지");
+ addressInfo.setBuildingNumber(16);
+ addressInfo.setBuildingSideNumber(14);
+ addressInfo.setBuildingUseClassification("주택");
+ addressInfo.setCityCountryName("종로구");
+ addressInfo.setCityCountryNameEng("Jongno-gu");
+ addressInfo.setCityName("서울특별시");
+ addressInfo.setCityNameEng("Seoul");
+ addressInfo.setClassificationApartmentBuildings("2");
+ addressInfo.setDetailBuildingName("7동");
+ addressInfo.setDetailBuildingNameChangeHistory("");
+ addressInfo.setExitXCoordinate(953042.185946);
+ addressInfo.setExitYCoordinate(1954799.009030);
+ addressInfo.setGroundFloorNumber(3);
+ addressInfo.setLivingStatus("1");
+ addressInfo.setMobileReasonCode("");
+ addressInfo.setRoadName("자하문로36길");
+ addressInfo.setRoadNameEng("Jahamun-ro 36-gil");
+ addressInfo.setTownCode("1111010100");
+ addressInfo.setTownMobileClassification("1");
+ addressInfo.setTownName("청운동");
+ addressInfo.setTownNameEng("Cheongun-dong");
+ addressInfo.setUndergroundFloorNumber(0);
+ addressInfo.setUndergroundStatus("0");
+ addressInfo.setZipCode("03046");
+
+ return addressInfo;
+ }
+
+ @Test
+ public void getTownInfoByShopIdTest_아이디로_주소_조회() {
+ final Long shopId = 777L;
+ AddressDTO addressInfo = generateAddressDTO();
+ List addressList = new ArrayList();
+ addressList.add(addressInfo);
+
+ given(addressMapper.findByShopId(shopId)).willReturn(addressList);
+
+ assertThat(addressService.getTownInfoByShopId(shopId), equalTo(addressList));
+ }
+
+ @Test
+ public void getAddressByZipAddressTest_지번주소로_주소_검색() {
+ AddressDTO addressInfo = generateAddressDTO();
+ List addressList = new ArrayList();
+ addressList.add(addressInfo);
+
+ GetAddressByZipRequest searchInfo = new GetAddressByZipRequest();
+ searchInfo.setBuildingNameForCity(addressInfo.getBuildingNameForCity());
+ searchInfo.setBuildingNumber(addressInfo.getBuildingNumber());
+ searchInfo.setBuildingSideNumber(addressInfo.getBuildingSideNumber());
+ searchInfo.setTownName(addressInfo.getTownName());
+
+ given(addressMapper.findByZipName(searchInfo)).willReturn(addressList);
+ assertThat(addressService.getAddressByZipAddress(searchInfo), equalTo(addressList));
+ }
+
+ @Test
+ public void getAddressByRoadNameTest_도로명주소로_주소_검색() {
+ AddressDTO addressInfo = generateAddressDTO();
+ List addressList = new ArrayList();
+ addressList.add(addressInfo);
+
+ GetAddressesByRoadRequest searchInfo = new GetAddressesByRoadRequest();
+ searchInfo.setBuildingNameForCity(addressInfo.getBuildingNameForCity());
+ searchInfo.setBuildingNumber(addressInfo.getBuildingNumber());
+ searchInfo.setBuildingSideNumber(addressInfo.getBuildingSideNumber());
+ searchInfo.setRoadName(addressInfo.getRoadName());
+
+ given(addressMapper.findByRoadName(searchInfo)).willReturn(addressList);
+ assertThat(addressService.getAddressByRoadName(searchInfo), equalTo(addressList));
+ }
+
+ @Test
+ public void getDistanceMeterTest_거리_계산() {
+ Position startPosition = Position.builder()
+ .xPos(0.0)
+ .yPos(0.0)
+ .build();
+
+ Position endPosition = Position.builder()
+ .xPos(300.0)
+ .yPos(400.0)
+ .build();
+
+ given(addressMapper.findPositionByAddressCode("11111111")).willReturn(startPosition);
+ given(addressMapper.findPositionByAddressCode("22222222")).willReturn(endPosition);
+
+ assertThat(addressService.getDistanceMeter("11111111", "22222222"), equalTo(500.0));
+ }
+
+ @Test
+ public void deliveryPriceTest_거리기반_배달료_계산() {
+ final double distances_300 = 300.0;
+ final double distances_1499_9 = 1499.9;
+ final double distances_1500 = 1500.0;
+ final double distances_1500_1 = 1500.1;
+ final double distances_2500 = 2500.0;
+ final double distances_1699 = 1699.0;
+
+ assertThat(addressService.deliveryPrice(distances_300), equalTo(2000L));
+ assertThat(addressService.deliveryPrice(distances_1499_9), equalTo(2000L));
+ assertThat(addressService.deliveryPrice(distances_1500), equalTo(2000L));
+ assertThat(addressService.deliveryPrice(distances_1500_1), equalTo(2000L));
+ assertThat(addressService.deliveryPrice(distances_2500), equalTo(4000L));
+ assertThat(addressService.deliveryPrice(distances_1699), equalTo(2200L));
+ }
+
+ @Test
+ public void deliveryPriceTest_아이디기반_배달료_계산() {
+ Position memberPosition = Position.builder()
+ .xPos(0.0)
+ .yPos(0.0)
+ .build();
+
+ Position shopPosition = Position.builder()
+ .xPos(3000.0)
+ .yPos(4000.0)
+ .build();
+
+ given(addressMapper.findPositionByMemberId("eric")).willReturn(memberPosition);
+ given(addressMapper.findPositionByShopId(555L)).willReturn(shopPosition);
+
+ assertThat(addressService.deliveryPrice("eric", 555L), equalTo(9000L));
+ }
+
+}
diff --git a/src/test/java/com/delfood/service/CartServiceTest.java b/src/test/java/com/delfood/service/CartServiceTest.java
index b58df32..c46e09a 100644
--- a/src/test/java/com/delfood/service/CartServiceTest.java
+++ b/src/test/java/com/delfood/service/CartServiceTest.java
@@ -1,8 +1,19 @@
package com.delfood.service;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.CoreMatchers.equalTo;
import static org.mockito.BDDMockito.given;
-
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import com.delfood.dao.CartDao;
+import com.delfood.dto.ItemDTO;
+import com.delfood.dto.ShopDTO;
+import com.delfood.dto.ItemDTO.CacheMenuDTO;
+import com.delfood.dto.ItemDTO.CacheOptionDTO;
+import com.delfood.dto.ItemDTO.CacheShopDTO;
+import com.delfood.error.exception.cart.DuplicateItemException;
+import com.google.common.collect.Lists;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -12,15 +23,147 @@
@RunWith(MockitoJUnitRunner.class)
public class CartServiceTest {
@InjectMocks
- CartService service;
+ CartService cartService;
@Mock
- CartDao dao;
+ CartDao cartDao;
+
+ /**
+ * id에 따른 Item을 생산하여 리턴한다.
+ * @author jun
+ * @param id 해당 아이디를 기반으로 메뉴와 옵션을 생산하여 아이템을 제작한다.
+ * @return
+ */
+ public ItemDTO generateItem(long id) {
+ final long menuId = id * 111;
+ final long shopId = 222L;
+ final long menuPrice = 11000L;
+ final long optionId = id;
+ final long[] optionPrices = {100L, 200L, 300L};
+
+ CacheMenuDTO menuInfo = new CacheMenuDTO(menuId, "테스트 메뉴 " + menuId, menuPrice);
+
+ List options = new ArrayList();
+ CacheOptionDTO optionInfo1 = new CacheOptionDTO(optionId, menuId + " 옵션 1", optionPrices[0]);
+ CacheOptionDTO optionInfo2 =
+ new CacheOptionDTO(optionId * 2L, menuId + " 옵션 2", optionPrices[1]);
+ CacheOptionDTO optionInfo3 =
+ new CacheOptionDTO(optionId * 3L, menuId + " 옵션 3", optionPrices[2]);
+ options.add(optionInfo1);
+ options.add(optionInfo2);
+ options.add(optionInfo3);
+
+ CacheShopDTO shopInfo = new CacheShopDTO(shopId, "테스트 매장 이름");
+
+ ItemDTO itemInfo = new ItemDTO(menuInfo, options, 1, menuPrice + 600L, shopInfo);
+
+ return itemInfo;
+ }
+
+ public ItemDTO generateItemAnotherShop() {
+ CacheMenuDTO menuInfo = new CacheMenuDTO(222L, "테스트 메뉴 222", 11000L);
+
+ List options = new ArrayList();
+ CacheOptionDTO optionInfo1 = new CacheOptionDTO(2L, "222 옵션 1", 100L);
+ CacheOptionDTO optionInfo2 = new CacheOptionDTO(2L, "222 옵션 2", 200L);
+ CacheOptionDTO optionInfo3 = new CacheOptionDTO(2L, "222 옵션 3", 300L);
+ options.add(optionInfo1);
+ options.add(optionInfo2);
+ options.add(optionInfo3);
+
+ CacheShopDTO shopInfo = new CacheShopDTO(123L, "테스트 매장 이름");
+
+ ItemDTO itemInfo = new ItemDTO(menuInfo, options, 1, 11600L, shopInfo);
+
+ return itemInfo;
+ }
+
+ @Test
+ public void addOrdersItemTest_장바구니에_메뉴_추가() {
+ ItemDTO item1 = generateItem(1L);
+ ItemDTO item2 = generateItem(2L);
+ given(cartDao.findPeekByMemberId("eric")).willReturn(item1);
+ cartService.addOrdersItem(item2, "eric");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void addOrdersItemTest_장바구니에_다른매장_메뉴_추가() {
+ ItemDTO item1 = generateItem(1L);
+ ItemDTO item2 = generateItemAnotherShop();
+ given(cartDao.findPeekByMemberId("eric")).willReturn(item1);
+ cartService.addOrdersItem(item2, "eric");
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void addOrdersItemTest_너무많은메뉴추가() {
+ given(cartDao.findPeekByMemberId("eric")).willReturn(generateItem(1L));
+ given(cartDao.findAllByMemberId("eric")).willReturn(Arrays.asList(
+ new ItemDTO[] {generateItem(1L), generateItem(1L), generateItem(1L), generateItem(1L),
+ generateItem(1L), generateItem(1L), generateItem(1L), generateItem(1L),
+ generateItem(1L), generateItem(1L), generateItem(1L), generateItem(1L)}));
+ cartService.addOrdersItem(generateItem(2L), "eric");
+ }
+ @Test(expected = DuplicateItemException.class)
+ public void addOrdersItemTest_같메뉴추가() {
+ given(cartDao.findPeekByMemberId("eric")).willReturn(generateItem(1L));
+ given(cartDao.findAllByMemberId("eric")).willReturn(Arrays.asList(
+ new ItemDTO[] {generateItem(1L)}));
+ cartService.addOrdersItem(generateItem(1L), "eric");
+ }
- // 로직이 확정되면 테스트코드를 다시 작성할 예정입니다
@Test
- public void mockTest() {
+ public void deleteCartMenuTest_장바구니_메뉴_삭제_인덱스() {
+ given(cartDao.getMenuCount("eric")).willReturn(5L);
+ given(cartDao.deleteByMemberIdAndIndex("eric", 1L)).willReturn(true);
+ cartService.deleteCartMenu("eric", 1L);
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void deleteCartMenuTest_장바구니_메뉴_삭제_인덱스_초과() {
+ given(cartDao.getMenuCount("eric")).willReturn(5L);
+ cartService.deleteCartMenu("eric", 6L);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void deleteCartMenuTest_장바구니_메뉴_삭제_redis에러() {
+ given(cartDao.getMenuCount("eric")).willReturn(5L);
+ given(cartDao.deleteByMemberIdAndIndex("eric", 1L)).willReturn(false);
+ cartService.deleteCartMenu("eric", 1L);
+ }
+
+ @Test
+ public void containsEqualItemTest_장바구니_동일아이템_포함여부_검사() {
+ given(cartDao.findAllByMemberId("eric"))
+ .willReturn(Arrays.asList(new ItemDTO[] {generateItem(1L)}));
+ assertThat(cartService.containsEqualItem("eric", generateItem(1L))).isEqualTo(true);
+ assertThat(cartService.containsEqualItem("eric", generateItem(2L))).isEqualTo(false);
+ }
+
+ @Test
+ public void allPriceTest_장바구니_총가격_계산() {
+ given(cartDao.findAllByMemberId("eric"))
+ .willReturn(Arrays.asList(new ItemDTO[] {generateItem(1L), generateItem(2L)}));
+ assertThat(cartService.allPrice("eric")).isEqualTo(23200L);
}
+
+ @Test
+ public void priceTest_아이템_가격계산() {
+ ItemDTO itemInfo = generateItem(1L);
+ assertThat(cartService.price(itemInfo)).isEqualTo(11600L);
+ }
+
+ @Test
+ public void menuPriceTest_아이템_메뉴만_가격계산() {
+ ItemDTO itemInfo = generateItem(1L);
+ assertThat(CartService.menuPrice(itemInfo)).isEqualTo(11000L);
+ }
+
+ @Test
+ public void menuPriceTest_아이템_옵션만_가격계산() {
+ ItemDTO itemInfo = generateItem(1L);
+ assertThat(CartService.optionsPrice(itemInfo)).isEqualTo(600L);
+ }
+
}
diff --git a/src/test/java/com/delfood/service/CouponIssueServiceTest.java b/src/test/java/com/delfood/service/CouponIssueServiceTest.java
new file mode 100644
index 0000000..8c6804b
--- /dev/null
+++ b/src/test/java/com/delfood/service/CouponIssueServiceTest.java
@@ -0,0 +1,47 @@
+package com.delfood.service;
+
+import static org.mockito.BDDMockito.given;
+import com.delfood.error.exception.DuplicateException;
+import com.delfood.mapper.CouponIssueMapper;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CouponIssueServiceTest {
+
+ @InjectMocks
+ private CouponIssueService couponIssueService;
+
+ @Mock
+ private CouponIssueMapper couponIssueMapper;
+
+ @Mock
+ private CouponService couponService;
+
+ @Test
+ public void createCouponIssue_쿠폰_발급_성공() {
+ String memberId = "eric";
+ long couponId = 1L;
+
+ given(couponIssueMapper.countCouponIssueByMemberIdAndCouponId(memberId, couponId))
+ .willReturn(0);
+ given(couponIssueMapper.insertCouponIssue(memberId, couponId)).willReturn(1);
+
+ couponIssueService.createCouponIssue(memberId, couponId);
+ }
+
+ @Test(expected = DuplicateException.class)
+ public void createCouponIssue_쿠폰_발급_실패_재발급() {
+ String memberId = "eric";
+ long couponId = 1L;
+
+ given(couponIssueMapper.countCouponIssueByMemberIdAndCouponId(memberId, couponId))
+ .willReturn(1);
+
+ couponIssueService.createCouponIssue(memberId, couponId);
+ }
+
+}
diff --git a/src/test/java/com/delfood/service/CouponServiceTest.java b/src/test/java/com/delfood/service/CouponServiceTest.java
new file mode 100644
index 0000000..84e686c
--- /dev/null
+++ b/src/test/java/com/delfood/service/CouponServiceTest.java
@@ -0,0 +1,129 @@
+package com.delfood.service;
+
+import static org.mockito.BDDMockito.given;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.delfood.dto.CouponDTO;
+import com.delfood.dto.CouponDTO.DiscountType;
+import com.delfood.dto.CouponDTO.Status;
+import com.delfood.error.exception.coupon.IssuedCouponExistException;
+import com.delfood.mapper.CouponMapper;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CouponServiceTest {
+
+ @InjectMocks
+ private CouponService couponService;
+
+ @Mock
+ private CouponMapper couponMapper;
+
+ @Mock
+ CouponIssueService couponIssueService;
+
+ /**
+ * 정상적으로 작동할 수 있는 쿠폰 DTO를 새로 생성하여 반환한다.
+ * @author jun
+ * @return
+ */
+ public static CouponDTO generateCoupon() {
+ CouponDTO couponInfo = new CouponDTO();
+
+ couponInfo.setId(111L);
+ couponInfo.setName("Test Coupon");
+ couponInfo.setDiscountType(DiscountType.PERCENT);
+ couponInfo.setDiscountValue(10L);
+ couponInfo.setCreatedAt(LocalDateTime.now().minusDays(1)); // 항상 오늘보다 하루 전 만들어진 쿠폰으로 설정한다.
+ couponInfo.setUpdatedAt(LocalDateTime.now().minusDays(1));
+ couponInfo.setEndAt(LocalDateTime.now().plusDays(1)); // 항상 오늘보다 하루 뒤 종료하도록 설정한다.
+ couponInfo.setStatus(Status.DEFAULT);
+
+ return couponInfo;
+ }
+
+ @Test
+ public void addCouponTest_쿠폰_추가_성공() {
+ CouponDTO couponInfo = generateCoupon();
+ given(couponMapper.insertCoupon(couponInfo)).willReturn(1L);
+
+ couponService.addCoupon(couponInfo);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void addCouponTest_쿠폰_추가_실패_종료일_설정_오류() {
+ CouponDTO couponInfo = generateCoupon();
+ couponInfo.setEndAt(couponInfo.getCreatedAt().minusDays(1));
+ given(couponMapper.insertCoupon(couponInfo)).willReturn(1L);
+
+ couponService.addCoupon(couponInfo);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void addCouponTest_쿠폰_추가_실패_할인율_101퍼센트() {
+ CouponDTO discountValueErrorCouponInfo = generateCoupon();
+ discountValueErrorCouponInfo.setDiscountValue(101L);
+
+ couponService.addCoupon(discountValueErrorCouponInfo);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void addCouponTest_쿠폰_추가_실패_할인율_0미만퍼센트() {
+ CouponDTO discountValueErrorCouponInfo = generateCoupon();
+ discountValueErrorCouponInfo.setDiscountValue(-1L);
+
+ couponService.addCoupon(discountValueErrorCouponInfo);
+ }
+
+ @Test
+ public void updateCouponNameAndEndAtTest_쿠폰_업데이트_성공() {
+ String updateName = "new Test Coupon Name";
+ LocalDateTime updateEndAt = LocalDateTime.now().plusDays(1L);
+ given(couponIssueService.isIssued(1L)).willReturn(false);
+ given(couponMapper.updateCouponNameAndEndAt(1L, updateName,
+ updateEndAt)).willReturn(1);
+
+ couponService.updateCouponNameAndEndAt(1L, updateName, updateEndAt);
+ }
+
+ @Test(expected = IssuedCouponExistException.class)
+ public void updateCouponNameAndEndAtTest_쿠폰_업데이트_실패_이미발행() {
+ String updateName = "new Test Coupon Name";
+ given(couponIssueService.isIssued(1L)).willReturn(true);
+
+ couponService.updateCouponNameAndEndAt(1L, updateName, LocalDateTime.now().plusDays(1L));
+ }
+
+ @Test
+ public void deleteCouponTest_쿠폰_삭제_성공() {
+ given(couponIssueService.isIssued(1L)).willReturn(false);
+ given(couponMapper.deleteCoupon(1L)).willReturn(1);
+
+ couponService.deleteCoupon(1L);
+ }
+
+ @Test(expected = IssuedCouponExistException.class)
+ public void deleteCouponTest_쿠폰_삭제_실패_이미발행() {
+ given(couponIssueService.isIssued(1L)).willReturn(true);
+
+ couponService.deleteCoupon(1L);
+ }
+
+ @Test
+ public void getAvaliableCouponsTest_사용가능_쿠폰_조회_성공() {
+ given(couponMapper.findByEndAtGreaterThanNow())
+ .willReturn(Arrays.asList(new CouponDTO[] {generateCoupon(), generateCoupon()}));
+
+ assertThat(couponService.getAvaliableCoupons())
+ .isNotEmpty()
+ .hasSize(2);
+ }
+
+
+}
diff --git a/src/test/java/com/delfood/service/MenuServiceTest.java b/src/test/java/com/delfood/service/MenuServiceTest.java
new file mode 100644
index 0000000..b1e703b
--- /dev/null
+++ b/src/test/java/com/delfood/service/MenuServiceTest.java
@@ -0,0 +1,135 @@
+package com.delfood.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.BDDMockito.given;
+
+import com.delfood.dto.MenuDTO;
+import com.delfood.dto.MenuDTO.Status;
+import com.delfood.dto.OptionDTO;
+import com.delfood.mapper.MenuMapper;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.LongStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MenuServiceTest {
+
+ @InjectMocks
+ MenuService service;
+
+ @Mock
+ MenuMapper mapper;
+
+ public MenuDTO generateMenu() {
+ MenuDTO menu = new MenuDTO();
+ menu.setId(1L);
+ menu.setMenuGroupId(1L);
+ menu.setContent("Test Menu Content");
+ menu.setOptionList(new ArrayList());
+ menu.setPhoto("Test Photo URL");
+ menu.setPrice(12000L);
+ menu.setPriority(1L);
+ menu.setStatus(Status.DEFAULT);
+ menu.setCreatedAt(LocalDateTime.now());
+ menu.setUpdatedAt(LocalDateTime.now());
+ return menu;
+ }
+
+ @Test
+ public void getMenuInfoTest_메뉴_조회_성공() {
+ MenuDTO menu = generateMenu();
+ given(mapper.findById(1L)).willReturn(menu);
+ given(mapper.findById(999L)).willReturn(null);
+ assertThat(service.getMenuInfo(1L)).isEqualTo(menu);
+ assertThat(service.getMenuInfo(999L)).isNull();
+ }
+
+ @Test
+ public void addMenuTest_메뉴_추가_성공() {
+ MenuDTO menu = generateMenu();
+ given(mapper.insertMenu(menu)).willReturn(menu.getId());
+ service.addMenu(menu);
+ }
+
+ @Test
+ public void deleteMenu_메뉴_삭제_성공() {
+ given(mapper.deleteMenu(1L)).willReturn(1);
+ service.deleteMenu(1L);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void deleteMenu_메뉴_삭제_실패() {
+ given(mapper.deleteMenu(1L)).willReturn(0);
+ service.deleteMenu(1L);
+ }
+
+ @Test
+ public void checkMenuTest_메뉴존재_체크_성공() {
+ given(mapper.checkMenu(1L, 1L)).willReturn(1);
+ service.checkMenu(1L, 1L);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void checkMenuTest_메뉴존재_체크_없음() {
+ given(mapper.checkMenu(1L, 1L)).willReturn(0);
+ service.checkMenu(1L, 1L);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void checkMenuTest_메뉴존재_체크_실패() {
+ given(mapper.checkMenu(1L, 1L)).willReturn(999);
+ service.checkMenu(1L, 1L);
+ }
+
+ @Test
+ public void updateMenuPriorityTest_메뉴_순서_변경_성공() {
+ given(mapper.totalCount(1L)).willReturn(3);
+ given(mapper.updateMenuPriority(anyLong(), anyInt())).willReturn(1);
+ List idList = LongStream.of(1,2,3).boxed().collect(Collectors.toList());
+
+ service.updateMenuPriority(1L, idList);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void updateMenuPriorityTest_메뉴_순서_변경_실패() {
+ given(mapper.totalCount(1L)).willReturn(0);
+ List idList = LongStream.of(1,2,3).boxed().collect(Collectors.toList());
+
+ service.updateMenuPriority(1L, idList);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void updateMenuPriorityTest_메뉴_순서_변경_실패2() {
+ given(mapper.totalCount(1L)).willReturn(3);
+ given(mapper.updateMenuPriority(anyLong(), anyInt())).willReturn(0);
+ List idList = LongStream.of(1,2,3).boxed().collect(Collectors.toList());
+
+ service.updateMenuPriority(1L, idList);
+ }
+
+ @Test
+ public void updateMenuTest_메뉴_정보_수정_성공() {
+ MenuDTO menu = generateMenu();
+ given(mapper.updateMenu(menu)).willReturn(1);
+ service.updateMenu(menu);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void updateMenuTest_메뉴_정보_수정_실패() {
+ MenuDTO menu = generateMenu();
+ given(mapper.updateMenu(menu)).willReturn(0);
+ service.updateMenu(menu);
+ }
+
+
+
+}
diff --git a/src/test/java/com/delfood/service/OptionServiceTest.java b/src/test/java/com/delfood/service/OptionServiceTest.java
new file mode 100644
index 0000000..87e1e50
--- /dev/null
+++ b/src/test/java/com/delfood/service/OptionServiceTest.java
@@ -0,0 +1,98 @@
+package com.delfood.service;
+
+import static org.junit.Assert.fail;
+import static org.mockito.BDDMockito.given;
+
+import com.delfood.dto.OptionDTO;
+import com.delfood.dto.OptionDTO.Status;
+import com.delfood.mapper.OptionMapper;
+import java.util.ArrayList;
+import java.util.List;
+import lombok.extern.log4j.Log4j2;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+@Log4j2
+public class OptionServiceTest {
+
+ @InjectMocks
+ OptionService service;
+
+ @Mock
+ OptionMapper mapper;
+
+ public OptionDTO generateOption() {
+ OptionDTO option = new OptionDTO();
+ option.setId(1L);
+ option.setMenuId(1L);
+ option.setName("Test Option Name");
+ option.setPrice(10000L);
+ option.setStatus(Status.DEFAULT);
+ return option;
+ }
+
+ @Test
+ public void addOptionTest_옵션_추가_성공() {
+ OptionDTO option = generateOption();
+ given(mapper.insertOption(option)).willReturn(1);
+ service.addOption(option);
+ }
+
+ @Test
+ public void addOptionTest_옵션_추가_실패_null() {
+ try {
+ OptionDTO option = generateOption();
+ option.setName(null);
+ service.addOption(option);
+ log.info("name null check 실패");
+ fail();
+ } catch (RuntimeException e) {
+ log.info("name null check 성공");
+ }
+
+ try {
+ OptionDTO option = generateOption();
+ option.setPrice(null);
+ service.addOption(option);
+ log.info("price null check 실패");
+ fail();
+ } catch (RuntimeException e) {
+ log.info("price null check 성공");
+ }
+
+ try {
+ OptionDTO option = generateOption();
+ option.setMenuId(null);
+ service.addOption(option);
+ log.info("menuId null check 실패");
+ fail();
+ } catch (RuntimeException e) {
+ log.info("menuId null check 성공");
+ }
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void addOptionTest_옵션_추가_실패_DB에러() {
+ OptionDTO option = generateOption();
+ given(mapper.insertOption(option)).willReturn(0);
+ service.addOption(option);
+ }
+
+ @Test
+ public void addOptionList_옵션_리스트_추가_성공() {
+ List options = new ArrayList();
+ for (long l = 1; l <= 3; l++) {
+ OptionDTO option = generateOption();
+ option.setId(l);
+ options.add(option);
+ }
+
+ given(mapper.insertOptionList(options, 1L)).willReturn(1);
+ service.addOptionList(options, 1L);
+ }
+
+}
diff --git a/src/test/java/com/delfood/service/OwnerServiceTest.java b/src/test/java/com/delfood/service/OwnerServiceTest.java
index 33483bc..5ced618 100644
--- a/src/test/java/com/delfood/service/OwnerServiceTest.java
+++ b/src/test/java/com/delfood/service/OwnerServiceTest.java
@@ -1,13 +1,10 @@
package com.delfood.service;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertThat;
import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import com.delfood.dto.OwnerDTO;
+import com.delfood.error.exception.DuplicateException;
import com.delfood.mapper.OwnerMapper;
import com.delfood.utils.SHA256Util;
import org.junit.Test;
@@ -26,38 +23,203 @@ public class OwnerServiceTest {
@Mock // mock 생성
OwnerMapper mapper;
+ /**
+ * owner 정보 생성.
+ * @return
+ */
+ public OwnerDTO generateOwner() {
+ return OwnerDTO.builder()
+ .id("ljy2134")
+ .password(SHA256Util.encryptSHA256("2134"))
+ .name("이진영")
+ .mail("asdf@naver.com")
+ .tel("010-3333-3333")
+ .build();
+ }
+
/**
* 회원가입 성공 테스트.
*/
@Test
public void signUp_success() {
- OwnerDTO ownerInfo = OwnerDTO.builder()
- .id("ljy2134")
- .password(SHA256Util.encryptSHA256("2134"))
- .name("이진영")
- .mail("asdf@naver.com")
- .tel("010-3333-3333")
- .build();
+ OwnerDTO ownerInfo = generateOwner();
given(mapper.insertOwner(ownerInfo)).willReturn(1);
+ given(mapper.idCheck(ownerInfo.getId())).willReturn(0);
+
service.signUp(ownerInfo);
}
/**
- * 회원가입 실패 테스트.
+ * 회원가입 실패 테스트. (DB insert 실패)
*/
@Test(expected = RuntimeException.class)
public void signUp_fail() {
- OwnerDTO ownerInfo = OwnerDTO.builder()
- .id("ljy2134")
- .password(SHA256Util.encryptSHA256("2134"))
- .name("이진영")
- .mail("asdf@naver.com")
- .tel("010-3333-3333")
- .build();
+ OwnerDTO ownerInfo = generateOwner();
+ given(mapper.idCheck(ownerInfo.getId())).willReturn(0);
given(mapper.insertOwner(ownerInfo)).willReturn(0);
+
service.signUp(ownerInfo);
}
+ /**
+ * 회원가입 실패 테스트. (아이디 중복 발생)
+ */
+ @Test(expected = RuntimeException.class)
+ public void signUp_fail2() {
+ OwnerDTO ownerInfo = generateOwner();
+
+ given(mapper.idCheck(ownerInfo.getId())).willReturn(1);
+
+ service.signUp(ownerInfo);
+ }
+
+ /**
+ * 아이디 중복 체크 성공 테스트.
+ */
+ @Test
+ public void isDuplicatedId_success() {
+ String duplicatedId = "duplicatedId";
+ String noDuplicatedId = "noDuplicatedId";
+ given(mapper.idCheck(duplicatedId)).willReturn(1);
+ given(mapper.idCheck(noDuplicatedId)).willReturn(0);
+
+ assertThat(service.isDuplicatedId(duplicatedId)).isTrue();
+ assertThat(service.isDuplicatedId(noDuplicatedId)).isFalse();
+ }
+
+ /**
+ * 사장 정보 조회 성공 테스트.
+ */
+ @Test
+ public void getOwner_success() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String password = ownerInfo.getPassword();
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(password)))
+ .willReturn(ownerInfo);
+ given(mapper.findById(id)).willReturn(ownerInfo);
+
+ assertThat(service.getOwner(id, password)).isEqualTo(ownerInfo);
+ assertThat(service.getOwner(id)).isEqualTo(ownerInfo);
+ }
+
+ /**
+ * 사장 이메일, 전화번호 수정 성공 테스트.
+ */
+ @Test
+ public void updateOwnerMailAndTel_success() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String password = ownerInfo.getPassword();
+ String mail = ownerInfo.getMail();
+ String tel = ownerInfo.getTel();
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(password))).willReturn(ownerInfo);
+ given(mapper.updateMailAndTel(id, mail, tel)).willReturn(1);
+
+ service.updateOwnerMailAndTel(id, password, mail, tel);
+ }
+
+ /**
+ * 사장 이메일, 전화번호 수정 실패 테스트. (아이디, 패스워드 검증 실패)
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void updateOwnerMailAndTel_fail() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String password = ownerInfo.getPassword();
+ String mail = ownerInfo.getMail();
+ String tel = ownerInfo.getTel();
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(password))).willReturn(null);
+
+ service.updateOwnerMailAndTel(id, password, mail, tel);
+ }
+
+ /**
+ * 사장 이메일, 전화번호 수정 실패 테스트. (DB update 실패)
+ */
+ @Test(expected = RuntimeException.class)
+ public void updateOwnerMailAndTel_fail2() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String password = ownerInfo.getPassword();
+ String mail = ownerInfo.getMail();
+ String tel = ownerInfo.getTel();
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(password))).willReturn(ownerInfo);
+ given(mapper.updateMailAndTel(id, mail, tel)).willReturn(0);
+
+ service.updateOwnerMailAndTel(id, password, mail, tel);
+ }
+
+
+ /**
+ * 사장 비밀번호 수정 성공 테스트.
+ */
+ @Test
+ public void updateOwnerPassword_success() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String beforePassword = ownerInfo.getPassword();
+ String afterPassword = "asdfasdf";
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(beforePassword)))
+ .willReturn(ownerInfo);
+ given(mapper.updatePassword(id, SHA256Util.encryptSHA256(afterPassword))).willReturn(1);
+
+ service.updateOwnerPassword(id, beforePassword, afterPassword);
+ }
+
+ /**
+ * 사장 비밀번호 수정 실패 테스트. (아이디와 기존 패스워드 매칭 실패)
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void updateOwnerPassword_fail() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String beforePassword = "strangePassword";
+ String afterPassword = "asdfasdf";
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(beforePassword)))
+ .willReturn(null);
+
+ service.updateOwnerPassword(id, beforePassword, afterPassword);
+ }
+
+ /**
+ * 사장 비밀번호 수정 실패 테스트. (변경 전 패스워드와 변경 후 패스워드가 일치)
+ */
+ @Test(expected = DuplicateException.class)
+ public void updateOwnerPassword_fail2() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String beforePassword = ownerInfo.getPassword();
+ String afterPassword = ownerInfo.getPassword();
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(beforePassword)))
+ .willReturn(ownerInfo);
+
+ service.updateOwnerPassword(id, beforePassword, afterPassword);
+ }
+
+ /**
+ * 사장 비밀번호 수정 실패 테스트. (변경 전 패스워드와 변경 후 패스워드가 일치)
+ */
+ @Test(expected = RuntimeException.class)
+ public void updateOwnerPassword_fail3() {
+ OwnerDTO ownerInfo = generateOwner();
+ String id = ownerInfo.getId();
+ String beforePassword = ownerInfo.getPassword();
+ String afterPassword = "afterPassword";
+
+ given(mapper.findByIdAndPassword(id, SHA256Util.encryptSHA256(beforePassword)))
+ .willReturn(ownerInfo);
+ given(mapper.updatePassword(id, SHA256Util.encryptSHA256(afterPassword))).willReturn(0);
+
+ service.updateOwnerPassword(id, beforePassword, afterPassword);
+ }
}
diff --git a/src/test/java/com/delfood/service/ShopServiceTest.java b/src/test/java/com/delfood/service/ShopServiceTest.java
new file mode 100644
index 0000000..47e6d41
--- /dev/null
+++ b/src/test/java/com/delfood/service/ShopServiceTest.java
@@ -0,0 +1,112 @@
+package com.delfood.service;
+
+import static org.mockito.BDDMockito.given;
+
+import com.delfood.dto.ShopDTO;
+import com.delfood.dto.ShopDTO.DeliveryType;
+import com.delfood.dto.ShopDTO.OrderType;
+import com.delfood.dto.ShopDTO.Status;
+import com.delfood.mapper.DeliveryLocationMapper;
+import com.delfood.mapper.ShopMapper;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ShopServiceTest {
+
+ @InjectMocks
+ private ShopService shopService;
+
+ @Mock
+ private ShopMapper shopMapper;
+
+ @Mock
+ private WorkService workService;
+
+ @Mock
+ private AddressService addressService;
+
+ @Mock
+ private DeliveryLocationMapper deliveryLocationMapper;
+
+ /**
+ * shop 정보 생성.
+ * @return
+ */
+ public ShopDTO generateShop() {
+ return ShopDTO.builder()
+ .id(999L)
+ .name("교촌치킨")
+ .deliveryType(DeliveryType.COMPANY_DELIVERY)
+ .signatureMenuId(1L)
+ .tel("02-2222-2222")
+ .addressCode("1111010100100010000031108")
+ .addressDetail("교촌치킨")
+ .bizNumber("111-11-11111")
+ .info("허니콤보 맛집")
+ .minOrderPrice(10000L)
+ .notice("배달료 3000원 붙습니다")
+ .operatingTime("11:00 ~ 02:00")
+ .ownerId("ljy2134")
+ .orderType(OrderType.THIS_PAYMENT)
+ .originInfo("닭 : 국내산")
+ .status(Status.DEFAULT)
+ .build();
+ }
+
+ /**
+ * 매장 추가 성공 테스트.
+ */
+ @Test
+ public void addShopSuccess() {
+ ShopDTO shopInfo = generateShop();
+
+ given(shopMapper.insertShop(shopInfo)).willReturn(1);
+
+ shopService.addShop(shopInfo);
+ }
+
+ /**
+ * 시그니처 메뉴가 없는 아이디 일 때 실패 테스트.
+ */
+ @Test(expected = RuntimeException.class)
+ public void addShopFailBeacauseMenuDoesNotExist() {
+ ShopDTO shopInfo = generateShop();
+ shopInfo.setSignatureMenuId(-1L);
+
+ given(shopMapper.insertShop(shopInfo)).willReturn(0);
+
+ shopService.addShop(shopInfo);
+ }
+
+ /**
+ * Owner가 없는 아이디 일 때 실패 테스트.
+ */
+ @Test(expected = RuntimeException.class)
+ public void addShopFailBeacauseOwnerDoesNotExist() {
+ ShopDTO shopInfo = generateShop();
+ shopInfo.setOwnerId("noExistId");
+
+ given(shopMapper.insertShop(shopInfo)).willReturn(0);
+
+ shopService.addShop(shopInfo);
+ }
+
+ /**
+ * address가 없는 아이디 일 때 실패 테스트.
+ */
+ @Test(expected = RuntimeException.class)
+ public void addShopFailBeacauseAddressDoesNotExist() {
+ ShopDTO shopInfo = generateShop();
+ shopInfo.setAddressCode("0000000000000000000000000");
+
+ given(shopMapper.insertShop(shopInfo)).willReturn(0);
+
+ shopService.addShop(shopInfo);
+ }
+
+}