From 573cde789fe1d05bca72746885dd9d950fc3f955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=A7=80=EB=AF=BC?= <108014449+stopmin@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:19:04 +0900 Subject: [PATCH 1/4] =?UTF-8?q?build:=20oauth2=20=ED=82=A4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #201 --- src/main/resources/application-prod.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index fbeaf830..012bafa6 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -23,15 +23,14 @@ spring: host: ${REDIS_HOST} security: + redirect_url: http://localhost:3000 oauth2: client: registration: kakao: client-id: ${KAKAO_CLIENT_ID} client-secret: ${KAKAO_CLIENT_SECRET} - scope: account_email - # - profile_nickname - # - account_email + scope: account_email, profile_nickname client-name: Kakao authorization-grant-type: authorization_code client-authentication-method: client_secret_post From 8ebccbfca4016c19e881cb6cd4b436d842f26ffd Mon Sep 17 00:00:00 2001 From: amm0124 <108533909+amm0124@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:23:38 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat=20:=20application-prod.yml=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 012bafa6..fad8c3de 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -34,7 +34,7 @@ spring: client-name: Kakao authorization-grant-type: authorization_code client-authentication-method: client_secret_post - redirect-uri: http://localhost:8080/login/oauth2/code/kakao + redirect-uri: https://api.poomasi.shop/login/oauth2/code/kakao provider: kakao: authorization-uri: https://kauth.kakao.com/oauth/authorize #카카오 로그인 화면 From e1a7b1da22a85af7878fa4f87b21770aeea2089d Mon Sep 17 00:00:00 2001 From: canyos <31244128+canyos@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:44:06 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20cart=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=ED=9B=84=20preorder=EB=A7=8C=EB=93=A4?= =?UTF-8?q?=EA=B8=B0=20(#205)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit stock 충분한지 검사 --- .../userdetail/UserDetailsServiceImpl.java | 1 + .../order/dto/request/CartOrderRequest.java | 11 ++ .../request/ProductOrderRegisterRequest.java | 11 +- .../order/entity/_product/OrderedProduct.java | 11 +- .../order/entity/_product/ProductOrder.java | 9 +- .../ProductOrderDetailsRepository.java | 10 ++ .../order/service/ProductOrderService.java | 51 +++++--- .../_cart/controller/CartController.java | 78 +++++------- .../_cart/dto/CartRegisterRequest.java | 21 ---- .../domain/product/_cart/dto/CartRequest.java | 7 -- .../product/_cart/dto/CartResponse.java | 4 +- .../domain/product/_cart/entity/Cart.java | 41 +++---- .../_cart/repository/CartRepository.java | 26 +--- .../product/_cart/service/CartService.java | 115 ++++++------------ 14 files changed, 169 insertions(+), 227 deletions(-) create mode 100644 src/main/java/poomasi/domain/order/dto/request/CartOrderRequest.java create mode 100644 src/main/java/poomasi/domain/order/repository/ProductOrderDetailsRepository.java delete mode 100644 src/main/java/poomasi/domain/product/_cart/dto/CartRegisterRequest.java delete mode 100644 src/main/java/poomasi/domain/product/_cart/dto/CartRequest.java diff --git a/src/main/java/poomasi/domain/auth/security/userdetail/UserDetailsServiceImpl.java b/src/main/java/poomasi/domain/auth/security/userdetail/UserDetailsServiceImpl.java index 86e2ff7b..2408468a 100644 --- a/src/main/java/poomasi/domain/auth/security/userdetail/UserDetailsServiceImpl.java +++ b/src/main/java/poomasi/domain/auth/security/userdetail/UserDetailsServiceImpl.java @@ -13,6 +13,7 @@ public class UserDetailsServiceImpl implements UserDetailsService { private final MemberRepository memberRepository; + public UserDetailsServiceImpl(MemberRepository memberRepository) { this.memberRepository = memberRepository; } diff --git a/src/main/java/poomasi/domain/order/dto/request/CartOrderRequest.java b/src/main/java/poomasi/domain/order/dto/request/CartOrderRequest.java new file mode 100644 index 00000000..4217116c --- /dev/null +++ b/src/main/java/poomasi/domain/order/dto/request/CartOrderRequest.java @@ -0,0 +1,11 @@ +package poomasi.domain.order.dto.request; + +import jdk.jfr.Description; + +@Description("cart에서 상품 정보 넘어오는 정보") +public record CartOrderRequest( + Long cartId, + Integer count +) { + +} diff --git a/src/main/java/poomasi/domain/order/dto/request/ProductOrderRegisterRequest.java b/src/main/java/poomasi/domain/order/dto/request/ProductOrderRegisterRequest.java index 55b5d106..3c8a2e0a 100644 --- a/src/main/java/poomasi/domain/order/dto/request/ProductOrderRegisterRequest.java +++ b/src/main/java/poomasi/domain/order/dto/request/ProductOrderRegisterRequest.java @@ -1,6 +1,11 @@ package poomasi.domain.order.dto.request; -public record ProductOrderRegisterRequest(String destinationAddress, - String destinationAddressDetail, - String deliveryRequest) { +import java.util.List; + +public record ProductOrderRegisterRequest( + List carts, + String destinationAddress, + String destinationAddressDetail, + String deliveryRequest) +{ } diff --git a/src/main/java/poomasi/domain/order/entity/_product/OrderedProduct.java b/src/main/java/poomasi/domain/order/entity/_product/OrderedProduct.java index 0f6fd4ba..251f65c0 100644 --- a/src/main/java/poomasi/domain/order/entity/_product/OrderedProduct.java +++ b/src/main/java/poomasi/domain/order/entity/_product/OrderedProduct.java @@ -4,6 +4,8 @@ import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -70,7 +72,8 @@ public class OrderedProduct implements Serializable { @Column(name = "invoice_number", nullable = true) private String invoiceNumber; - private OrderedProductStatus orderedProductStatus = OrderedProductStatus.PENDING_SELLER_APPROVAL; + @Enumerated(EnumType.STRING) + private OrderedProductStatus orderedProductStatus; @Description("TODO : product의 delivery fee를 참조해야 한다.") private BigDecimal deliveryFee; @@ -96,8 +99,8 @@ public class OrderedProduct implements Serializable { // 배송 상태 적절히 변경해야 함 @Builder - public OrderedProduct(Product product, ProductOrder productOrder, String productDescription, - String productName, BigDecimal price, Integer count) { + public OrderedProduct(Product product, ProductOrder productOrder, OrderedProductStatus orderedProductStatus, String productDescription, + BigDecimal deliveryFee, String productName, BigDecimal price, Integer count) { this.product = product; this.productOrder = productOrder; this.productDescription = productDescription; @@ -105,6 +108,8 @@ public OrderedProduct(Product product, ProductOrder productOrder, String product this.price = price; this.count = count; this.review = null; + this.orderedProductStatus = orderedProductStatus; + this.deliveryFee = deliveryFee; } public void setInvoiceNumber(String invoiceNumber) { diff --git a/src/main/java/poomasi/domain/order/entity/_product/ProductOrder.java b/src/main/java/poomasi/domain/order/entity/_product/ProductOrder.java index 90c237e2..0ebdb809 100644 --- a/src/main/java/poomasi/domain/order/entity/_product/ProductOrder.java +++ b/src/main/java/poomasi/domain/order/entity/_product/ProductOrder.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; +import java.util.ArrayList; import jdk.jfr.Description; import lombok.Builder; import lombok.Getter; @@ -25,13 +26,13 @@ public class ProductOrder extends AbstractOrder { @Column(name = "merchant_uid") @Description("서버 내부 주문 id(아임포트 id)") - private String merchantUid = "p" + new Date().getTime(); + private String merchantUid; @Column(name = "ordered_products_id") @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) - private List orderedProducts; + private List orderedProducts = new ArrayList<>(); - @OneToOne + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "product_order_details_id") // 외래 키 지정 @Description("상품 배송지, 요청 사항") private ProductOrderDetails productOrderDetails; @@ -41,7 +42,7 @@ public ProductOrder(){ } public void addOrderedProduct(OrderedProduct orderedProduct) { - this.orderedProducts.add(orderedProduct); + orderedProducts.add(orderedProduct); } public void setMerchantUid(String merchantUid) { diff --git a/src/main/java/poomasi/domain/order/repository/ProductOrderDetailsRepository.java b/src/main/java/poomasi/domain/order/repository/ProductOrderDetailsRepository.java new file mode 100644 index 00000000..e8b2ff08 --- /dev/null +++ b/src/main/java/poomasi/domain/order/repository/ProductOrderDetailsRepository.java @@ -0,0 +1,10 @@ +package poomasi.domain.order.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.web.bind.annotation.RequestMapping; +import poomasi.domain.order.entity._product.ProductOrderDetails; + +@RequestMapping +public interface ProductOrderDetailsRepository extends JpaRepository { + +} diff --git a/src/main/java/poomasi/domain/order/service/ProductOrderService.java b/src/main/java/poomasi/domain/order/service/ProductOrderService.java index e8baf045..101f8582 100644 --- a/src/main/java/poomasi/domain/order/service/ProductOrderService.java +++ b/src/main/java/poomasi/domain/order/service/ProductOrderService.java @@ -1,5 +1,7 @@ package poomasi.domain.order.service; +import java.util.ArrayList; +import java.util.Date; import jdk.jfr.Description; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -9,27 +11,33 @@ import org.springframework.transaction.annotation.Transactional; import poomasi.domain.auth.security.userdetail.UserDetailsImpl; import poomasi.domain.member.entity.Member; +import poomasi.domain.order.dto.request.CartOrderRequest; import poomasi.domain.order.dto.request.ProductOrderRegisterRequest; import poomasi.domain.order.dto.response.OrderDetailsResponse; import poomasi.domain.order.dto.response.OrderProductDetailsResponse; import poomasi.domain.order.dto.response.OrderResponse; import poomasi.domain.order.entity.PaymentStatus; import poomasi.domain.order.entity._product.OrderedProduct; +import poomasi.domain.order.entity._product.OrderedProductStatus; import poomasi.domain.order.entity._product.ProductOrder; import poomasi.domain.order.entity._product.ProductOrderDetails; import poomasi.domain.order.repository.OrderedProductRepository; +import poomasi.domain.order.repository.ProductOrderDetailsRepository; import poomasi.domain.order.repository.ProductOrderRepository; import poomasi.domain.product._cart.entity.Cart; import poomasi.domain.product._cart.repository.CartRepository; +import poomasi.domain.product._cart.service.CartService; import poomasi.domain.product.entity.Product; import poomasi.domain.product.repository.ProductRepository; import poomasi.global.error.ApplicationException; +import poomasi.global.error.BusinessError; import poomasi.global.error.BusinessException; import poomasi.payment.dto.request.PaymentPreRegisterRequest; import java.math.BigDecimal; import java.util.List; import java.util.stream.Collectors; +import poomasi.payment.entity.Payment; import static poomasi.global.error.ApplicationError.PAYMENT_NOT_FOUND; import static poomasi.global.error.BusinessError.*; @@ -41,68 +49,79 @@ public class ProductOrderService { private final ProductOrderRepository productOrderRepository; - private final CartRepository cartRepository; + private final CartService cartService; private final ProductRepository productRepository; private final OrderedProductRepository orderedProductRepository; + private final ProductOrderDetailsRepository productOrderDetailsRepository; @Transactional public PaymentPreRegisterRequest productPreOrderRegister(ProductOrderRegisterRequest productOrderRegisterRequest) { Member member = getMember(); - Long memberId = member.getId(); - List cartList = cartRepository.findByMemberIdAndSelected(memberId); + List idList = productOrderRegisterRequest.carts().stream().map(CartOrderRequest::cartId).toList(); + List cartList = cartService.getCartsByIdList(idList); String destinationAddress = productOrderRegisterRequest.destinationAddress(); String destinationAddressDetail = productOrderRegisterRequest.destinationAddressDetail(); String deliveryRequest = productOrderRegisterRequest.deliveryRequest(); - ProductOrder productOrder = new ProductOrder() + ProductOrder productOrder = ProductOrder .builder() + .merchantUid("p" + new Date().getTime()) + .payment(new Payment()) + .totalAmount(BigDecimal.ZERO) .member(member) + .orderedProducts(new ArrayList<>()) .build(); + productOrderRepository.save(productOrder); - ProductOrderDetails productOrderDetails = new ProductOrderDetails() + ProductOrderDetails productOrderDetails = ProductOrderDetails .builder() + .productOrder(productOrder) .destinationAddress(destinationAddress) .destinationAddressDetail(destinationAddressDetail) .deliveryRequest(deliveryRequest) .build(); + productOrderDetailsRepository.save(productOrderDetails); + productOrder.setProductOrderDetails(productOrderDetails); //cart에 있는 총 가격 계산하기 BigDecimal totalPrice = BigDecimal.ZERO; // cart 돌면서 productOrder details 추가 - for (Cart cart : cartList) { - Long productId = cart.getProductId(); - Product product = productRepository.findById(productId) - .orElseThrow(() -> new BusinessException(PRODUCT_NOT_FOUND)); + for (int i=0 ; i productStock) { throw new BusinessException(PRODUCT_STOCK_ZERO); } String productDescription = product.getDescription(); - Integer count = cart.getCount(); String productName = product.getName(); - BigDecimal price = product.getPrice(); + BigDecimal price = product.getPrice().multiply(BigDecimal.valueOf((long) quantityInCart)); //TODO : Store store = product.getStore(); OrderedProduct orderedProduct = OrderedProduct .builder() .product(product) + .orderedProductStatus(OrderedProductStatus.PENDING_SELLER_APPROVAL) + .deliveryFee(product.getShippingFee()) .productOrder(productOrder) //.store(store) .productDescription(productDescription) .productName(productName) .price(price) - .count(count) + .count(quantityInCart) .build(); productOrder.addOrderedProduct(orderedProduct); @@ -112,6 +131,8 @@ public PaymentPreRegisterRequest productPreOrderRegister(ProductOrderRegisterReq productOrder.setCheckSum(totalPrice); productOrderRepository.save(productOrder); + productOrder.setProductOrderDetails(productOrderDetails); + String merchantUid = productOrder.getMerchantUid(); return new PaymentPreRegisterRequest(merchantUid, totalPrice); } diff --git a/src/main/java/poomasi/domain/product/_cart/controller/CartController.java b/src/main/java/poomasi/domain/product/_cart/controller/CartController.java index fb8a187c..1bb4edd1 100644 --- a/src/main/java/poomasi/domain/product/_cart/controller/CartController.java +++ b/src/main/java/poomasi/domain/product/_cart/controller/CartController.java @@ -4,83 +4,61 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Controller; 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 poomasi.domain.product._cart.dto.CartRegisterRequest; -import poomasi.domain.product._cart.dto.CartRequest; +import org.springframework.web.bind.annotation.RequestMapping; +import poomasi.domain.auth.security.userdetail.UserDetailsImpl; +import poomasi.domain.member.entity.Member; import poomasi.domain.product._cart.dto.CartResponse; import poomasi.domain.product._cart.service.CartService; @Controller @RequiredArgsConstructor +@RequestMapping("/api/cart") public class CartController { private final CartService cartService; - //장바구니 정보 - @GetMapping("/api/cart") - public ResponseEntity getCart() { - List cart = cartService.getCart(); + //장바구니 모든 정보 + @GetMapping("") + public ResponseEntity getCart(@AuthenticationPrincipal UserDetailsImpl userDetails) { + Member member = userDetails.getMember(); + List cart = cartService.getCart(member); return ResponseEntity.ok().body(cart); } - //장바구니 선택한거만 가격 - @GetMapping("/api/cart/price") - public ResponseEntity getPrice() { - Integer price = cartService.getPrice(); - return ResponseEntity.ok().body(price); - } - //장바구니 추가 - @PostMapping("/api/cart") - public ResponseEntity addCart(@RequestBody CartRegisterRequest cartRequest) { - Long cartId = cartService.addCart(cartRequest); + @PostMapping("/{productId}") + public ResponseEntity addCart( + @AuthenticationPrincipal UserDetailsImpl userDetails, + @PathVariable Long productId) { + Member member = userDetails.getMember(); + Long cartId = cartService.addCart(member, productId); return new ResponseEntity<>(cartId, HttpStatus.CREATED); } - //장바구니 선택/해제 - @PostMapping("/api/cart/select") - public ResponseEntity changeSelect(@RequestBody CartRequest cartRequest) { - cartService.changeSelect(cartRequest); - return ResponseEntity.ok().build(); - } - //장바구니 삭제 - @DeleteMapping("/api/cart") - public ResponseEntity removeCart(@RequestBody CartRequest cartRequest) { - cartService.deleteCart(cartRequest); - return ResponseEntity.ok().build(); - } - - //장바구니 선택된거 삭제 - @DeleteMapping("/api/cart/selected") - public ResponseEntity removeSelected() { - cartService.removeSelected(); + @DeleteMapping("/{cartId}") + public ResponseEntity removeCart( + @AuthenticationPrincipal UserDetailsImpl userDetails, + @PathVariable Long cartId) { + Member member = userDetails.getMember(); + cartService.deleteCart(member, cartId); return ResponseEntity.ok().build(); } //장바구니 전부 삭제 - @DeleteMapping("/api/cart/all") - public ResponseEntity removeAllCart() { - cartService.deleteAll(); - return ResponseEntity.ok().build(); - } - - //장바구니 물건 개수 추가 - @PatchMapping("/api/cart/add") - public ResponseEntity addCount(@RequestBody CartRequest cartRequest) { - cartService.addCount(cartRequest); + @DeleteMapping("/all") + public ResponseEntity removeAllCart(@AuthenticationPrincipal UserDetailsImpl userDetails) { + Member member = userDetails.getMember(); + cartService.deleteAll(member); return ResponseEntity.ok().build(); } - //장바구니 물건 개수 감소 - @PatchMapping("/api/cart/sub") - public ResponseEntity subCount(@RequestBody CartRequest cartRequest) { - cartService.subCount(cartRequest); - return ResponseEntity.ok().build(); - } } diff --git a/src/main/java/poomasi/domain/product/_cart/dto/CartRegisterRequest.java b/src/main/java/poomasi/domain/product/_cart/dto/CartRegisterRequest.java deleted file mode 100644 index 90189d7d..00000000 --- a/src/main/java/poomasi/domain/product/_cart/dto/CartRegisterRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package poomasi.domain.product._cart.dto; - -import lombok.extern.slf4j.Slf4j; -import poomasi.domain.member.entity.Member; -import poomasi.domain.product._cart.entity.Cart; - -@Slf4j -public record CartRegisterRequest( - Long productId, - Integer count -) { - - public Cart toEntity(Member member) { - return Cart.builder() - .memberId(member.getId()) - .productId(productId) - .selected(Boolean.TRUE) - .count(count != null ? count : 1) - .build(); - } -} diff --git a/src/main/java/poomasi/domain/product/_cart/dto/CartRequest.java b/src/main/java/poomasi/domain/product/_cart/dto/CartRequest.java deleted file mode 100644 index 98148a41..00000000 --- a/src/main/java/poomasi/domain/product/_cart/dto/CartRequest.java +++ /dev/null @@ -1,7 +0,0 @@ -package poomasi.domain.product._cart.dto; - -public record CartRequest( - Long cartId -) { - -} diff --git a/src/main/java/poomasi/domain/product/_cart/dto/CartResponse.java b/src/main/java/poomasi/domain/product/_cart/dto/CartResponse.java index ae43a7eb..09db1b78 100644 --- a/src/main/java/poomasi/domain/product/_cart/dto/CartResponse.java +++ b/src/main/java/poomasi/domain/product/_cart/dto/CartResponse.java @@ -6,9 +6,7 @@ public record CartResponse( Long cartId, String productName, BigDecimal productPrice, - Integer productCount, - Boolean isSelected, - String farmName + String storeName ) { } diff --git a/src/main/java/poomasi/domain/product/_cart/entity/Cart.java b/src/main/java/poomasi/domain/product/_cart/entity/Cart.java index 7a50b0bb..69779c35 100644 --- a/src/main/java/poomasi/domain/product/_cart/entity/Cart.java +++ b/src/main/java/poomasi/domain/product/_cart/entity/Cart.java @@ -1,12 +1,21 @@ package poomasi.domain.product._cart.entity; +import jakarta.persistence.CascadeType; +import jakarta.persistence.ConstraintMode; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToOne; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import poomasi.domain.member.entity.Member; +import poomasi.domain.product.entity.Product; @Entity @NoArgsConstructor @@ -17,32 +26,18 @@ public class Cart { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - private Boolean selected; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) + private Member member; - private Long memberId; - - private Long productId; - - private Integer count; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) + private Product product; @Builder - public Cart(Long id, Long memberId, Long productId, Boolean selected, Integer count) { + public Cart(Long id, Member member, Product product) { this.id = id; - this.memberId = memberId; - this.productId = productId; - this.selected = selected; - this.count = count; - } - - public void addCount() { - this.count += 1; - } - - public void subCount() { - this.count -= 1; - } - - public void changeSelect() { - this.selected = !this.selected; + this.member = member; + this.product = product; } } diff --git a/src/main/java/poomasi/domain/product/_cart/repository/CartRepository.java b/src/main/java/poomasi/domain/product/_cart/repository/CartRepository.java index 726c0b87..6bd478b1 100644 --- a/src/main/java/poomasi/domain/product/_cart/repository/CartRepository.java +++ b/src/main/java/poomasi/domain/product/_cart/repository/CartRepository.java @@ -7,36 +7,22 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import poomasi.domain.member.entity.Member; import poomasi.domain.product._cart.dto.CartResponse; import poomasi.domain.product._cart.entity.Cart; @Repository public interface CartRepository extends JpaRepository { - @Query("SELECT new poomasi.domain.product._cart.dto.CartResponse(c.id, p.name, p.price, c.count, c.selected,f.name) " - + - "FROM Cart c " + - "INNER JOIN Product p ON c.productId = p.id " + - "INNER JOIN Farm f ON f.ownerId = :memberId") - List findByMemberId(Long memberId); + @Query("SELECT new poomasi.domain.product._cart.dto.CartResponse(c.id, c.product.name, c.product.price, c.member.store.name) from Cart c where c.member = :member") + List findByMember(Member member); - @Query("select sum(p.price * c.count) from Cart c inner join Product p on c.productId = p.id where c.memberId = :memberId and c.selected = true") - Integer getPrice(Long memberId); - - @Query("select c from Cart c where c.memberId = :memberId and c.productId = :productId") Optional findByMemberIdAndProductId(Long memberId, Long productId); - @Modifying - @Transactional - @Query("delete from Cart c where c.memberId = :memberId") - void deleteAllByMemberId(Long memberId); + @Query("SELECT e FROM Cart e WHERE e.id IN :ids") + List getCartsByIdList(List ids); @Modifying @Transactional - @Query("delete from Cart c where c.memberId = :memberId and c.selected = true") - void deleteByMemberIdAndSelected(Long memberId); - - // order 만들 때 사용할 거 - @Query("select c from Cart c where c.memberId = :memberId and c.selected = true") - List findByMemberIdAndSelected(Long memberId); + void deleteAllByMemberId(Long memberId); } diff --git a/src/main/java/poomasi/domain/product/_cart/service/CartService.java b/src/main/java/poomasi/domain/product/_cart/service/CartService.java index 51071f97..75610211 100644 --- a/src/main/java/poomasi/domain/product/_cart/service/CartService.java +++ b/src/main/java/poomasi/domain/product/_cart/service/CartService.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Optional; +import jdk.jfr.Description; import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -9,13 +10,10 @@ import org.springframework.transaction.annotation.Transactional; import poomasi.domain.auth.security.userdetail.UserDetailsImpl; import poomasi.domain.member.entity.Member; -import poomasi.domain.product._cart.dto.CartRegisterRequest; -import poomasi.domain.product._cart.dto.CartRequest; import poomasi.domain.product._cart.dto.CartResponse; import poomasi.domain.product._cart.entity.Cart; import poomasi.domain.product._cart.repository.CartRepository; import poomasi.domain.product.entity.Product; -import poomasi.domain.product.repository.ProductRepository; import poomasi.domain.product.service.ProductService; import poomasi.global.error.BusinessError; import poomasi.global.error.BusinessException; @@ -27,62 +25,54 @@ public class CartService { private final CartRepository cartRepository; private final ProductService productService; + public List getCart(Member member) { + return cartRepository.findByMember(member); + } + @Transactional - public Long addCart(CartRegisterRequest cartRequest) { - Member member = getMember(); - Product product = getProductById(cartRequest.productId()); - - Optional cartOptional = cartRepository.findByMemberIdAndProductId(member.getId(), - product.getId()); - if (cartOptional.isPresent()) { - Cart cart = cartOptional.get(); - return cart.getId(); - } + public Long addCart(Member member, Long productId) { + Product product = getProductById(productId); + + Optional cartOptional = + cartRepository.findByMemberIdAndProductId(member.getId(), product.getId()); + + //이미 담은 상품임 + if (cartOptional.isPresent()) + return cartOptional.get().getId(); + + + Cart cart = Cart.builder() + .member(member) + .product(product) + .build(); - Cart cart = cartRequest.toEntity(member); - if (product.getStock() < cart.getCount()) { - throw new BusinessException(BusinessError.PRODUCT_STOCK_ZERO); - } cart = cartRepository.save(cart); return cart.getId(); - } @Transactional - public void deleteCart(CartRequest cartRequest) { - Member member = getMember(); - Cart cart = getCartById(cartRequest.cartId()); + @Description("카트 한 개 삭제") + public void deleteCart(Member member, Long cartId) { + Cart cart = getCartById(cartId); checkAuth(member, cart); cartRepository.delete(cart); } - private void checkAuth(Member member, Cart cart) { - if (!member.getId().equals(cart.getMemberId())) { - throw new BusinessException(BusinessError.MEMBER_ID_MISMATCH); - } - } @Transactional - public void addCount(CartRequest cartRequest) { - Member member = getMember(); - Cart cart = getCartById(cartRequest.cartId()); - Product product = getProductById(cart.getProductId()); - if (product.getStock().equals(cart.getCount())) { - throw new BusinessException(BusinessError.PRODUCT_STOCK_ZERO); - } - checkAuth(member, cart); - cart.addCount(); + @Description("전부 삭제") + public void deleteAll(Member member) { + cartRepository.deleteAllByMemberId(member.getId()); } - @Transactional - public void subCount(CartRequest cartRequest) { - Member member = getMember(); - Cart cart = getCartById(cartRequest.cartId()); - checkAuth(member, cart); - cart.subCount(); + @Description("요청한 사람이랑 카트 주인이랑 같은지 확인") + private void checkAuth(Member member, Cart cart) { + if (!member.getId().equals(cart.getMember().getId())) { + throw new BusinessException(BusinessError.MEMBER_ID_MISMATCH); + } } - private Cart getCartById(Long cartId) { + public Cart getCartById(Long cartId) { return cartRepository.findById(cartId) .orElseThrow(() -> new BusinessException(BusinessError.CART_NOT_FOUND)); } @@ -91,41 +81,10 @@ private Product getProductById(Long productId) { return productService.findProductById(productId); } - public List getCart() { - Member member = getMember(); - return cartRepository.findByMemberId(member.getId()); - } - - private Member getMember() { - Authentication authentication = SecurityContextHolder - .getContext().getAuthentication(); - Object impl = authentication.getPrincipal(); - Member member = ((UserDetailsImpl) impl).getMember(); - return member; - } - - @Transactional - public void changeSelect(CartRequest cartRequest) { - Member member = getMember(); - Cart cart = getCartById(cartRequest.cartId()); - checkAuth(member, cart); - cart.changeSelect(); - } - - public Integer getPrice() { - Member member = getMember(); - return cartRepository.getPrice(member.getId()); - } - - @Transactional - public void deleteAll() { - Member member = getMember(); - cartRepository.deleteAllByMemberId(member.getId()); - } - - @Transactional - public void removeSelected() { - Member member = getMember(); - cartRepository.deleteByMemberIdAndSelected(member.getId()); + @Description("order 만들 때 사용할 거") + public List getCartsByIdList(List ids) { + List orderList = cartRepository.getCartsByIdList(ids); + cartRepository.deleteAll(orderList); + return orderList; } } From 0a5e67bbaa1b8d19397f2bada80dc5e4a0b7ee33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=A7=80=EB=AF=BC?= <108014449+stopmin@users.noreply.github.com> Date: Thu, 14 Nov 2024 23:47:12 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[=EB=86=8D=EC=9E=A5]=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EC=9E=91=EC=97=85=20(#200)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 농장 등록 API 명세 수정 #196 * feat: 농장 수정 API #196 * test: 테스트 코드 수정 #196 * feat: 농장 등록 API 수정 #196 * feat: 농장 명세 수정 #196 * test: 통과시키도록 수정 #196 * feat: 사업자 등록 번호 추가 #196 --- .../farm/controller/FarmController.java | 4 +- .../farm/controller/FarmFarmerController.java | 14 ++-- .../dto/request/FarmInfoAggregateRequest.java | 69 ++++++++++++++++++ .../dto/request/FarmInfoUpdateRequest.java | 9 +++ .../farm/dto/request/FarmRegisterRequest.java | 10 ++- .../farm/dto/response/FarmDetailResponse.java | 4 +- .../response/FarmInfoAggregateResponse.java | 36 ++++++++++ .../farm/dto/response/FarmResponse.java | 25 +++---- .../poomasi/domain/farm/entity/FarmInfo.java | 8 +++ .../farm/service/FarmFarmerService.java | 70 +++++++++++++------ .../farm/service/FarmPlatformService.java | 5 +- .../domain/farm/service/FarmService.java | 12 ++++ .../domain/order/entity/_farm/FarmOrder.java | 2 +- .../order/entity/_farm/FarmOrderDetails.java | 2 +- .../order/service/ProductOrderService.java | 2 +- .../product/_intro/entity/ProductIntro.java | 2 +- .../domain/product/entity/Product.java | 2 +- .../store/repository/StoreRepository.java | 2 +- .../poomasi/global/error/BusinessError.java | 3 + .../farm/service/FarmFarmerServiceTest.java | 54 ++++++++++---- .../farm/service/FarmPlatformServiceTest.java | 14 +++- 21 files changed, 279 insertions(+), 70 deletions(-) create mode 100644 src/main/java/poomasi/domain/farm/dto/request/FarmInfoAggregateRequest.java create mode 100644 src/main/java/poomasi/domain/farm/dto/request/FarmInfoUpdateRequest.java create mode 100644 src/main/java/poomasi/domain/farm/dto/response/FarmInfoAggregateResponse.java diff --git a/src/main/java/poomasi/domain/farm/controller/FarmController.java b/src/main/java/poomasi/domain/farm/controller/FarmController.java index 38b02ee1..0f81220e 100644 --- a/src/main/java/poomasi/domain/farm/controller/FarmController.java +++ b/src/main/java/poomasi/domain/farm/controller/FarmController.java @@ -2,7 +2,6 @@ import jdk.jfr.Description; import lombok.RequiredArgsConstructor; -import org.hibernate.annotations.Comment; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -10,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import poomasi.domain.farm.dto.response.FarmDetailResponse; +import poomasi.domain.farm.dto.response.FarmResponse; import poomasi.domain.farm.service.FarmPlatformService; @@ -22,7 +22,7 @@ public class FarmController { @Description("Farm 단건 조회") @GetMapping("/{farmId}") - public ResponseEntity getFarm(@PathVariable Long farmId) { + public ResponseEntity getFarm(@PathVariable Long farmId) { return ResponseEntity.ok(farmPlatformService.getFarmByFarmId(farmId)); } diff --git a/src/main/java/poomasi/domain/farm/controller/FarmFarmerController.java b/src/main/java/poomasi/domain/farm/controller/FarmFarmerController.java index aff2f655..4be4476c 100644 --- a/src/main/java/poomasi/domain/farm/controller/FarmFarmerController.java +++ b/src/main/java/poomasi/domain/farm/controller/FarmFarmerController.java @@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.*; import poomasi.domain.auth.security.userdetail.UserDetailsImpl; import poomasi.domain.farm.dto.request.FarmInfoRegisterRequest; +import poomasi.domain.farm.dto.request.FarmInfoUpdateRequest; import poomasi.domain.farm.dto.request.FarmRegisterRequest; import poomasi.domain.farm.dto.request.FarmUpdateRequest; import poomasi.domain.farm.service.FarmFarmerService; @@ -19,8 +20,6 @@ @RequestMapping("/api/farm") public class FarmFarmerController { private final FarmFarmerService farmFarmerService; - private final FarmScheduleService farmScheduleService; - @Secured("ROLE_FARMER") @PostMapping("") @@ -29,19 +28,18 @@ public ResponseEntity registerFarm( @Valid @RequestBody FarmRegisterRequest request) { Member member = userDetails.getMember(); return ResponseEntity.ok(farmFarmerService.registerFarm(member, request)); - } @Secured("ROLE_FARMER") - @PostMapping("/info") - public ResponseEntity registerFarmInfo( + @PostMapping("/info/update") + public ResponseEntity updateFarmInfo( @AuthenticationPrincipal UserDetailsImpl userDetails, - @Valid @RequestBody FarmInfoRegisterRequest request) { + @Valid @RequestBody FarmInfoUpdateRequest request) { Member member = userDetails.getMember(); - return ResponseEntity.ok(farmFarmerService.registerFarmInfo(member, request)); - + return ResponseEntity.ok(farmFarmerService.updateFarmInfo(member, request)); } + @Secured("ROLE_FARMER") @PostMapping("/update") public ResponseEntity updateFarm( diff --git a/src/main/java/poomasi/domain/farm/dto/request/FarmInfoAggregateRequest.java b/src/main/java/poomasi/domain/farm/dto/request/FarmInfoAggregateRequest.java new file mode 100644 index 00000000..bc8865fb --- /dev/null +++ b/src/main/java/poomasi/domain/farm/dto/request/FarmInfoAggregateRequest.java @@ -0,0 +1,69 @@ +package poomasi.domain.farm.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Builder; +import poomasi.global.error.BusinessException; + +import java.util.ArrayList; +import java.util.List; + +import static poomasi.global.error.BusinessError.FARM_INFO_DETAIL_SIZE_MISMATCH; + +@Builder +public record FarmInfoAggregateRequest( + @NotBlank(message = "제목은 필수 입력값입니다.") + String title, + + @NotBlank(message = "대표 이미지는 필수 입력값입니다.") + String mainImage, + + @NotNull(message = "세부 제목 리스트는 null일 수 없습니다.") + @Size(min = 3, max = 3, message = "세부 제목은 3개여야 합니다.") + List detailTitles, + + @NotNull(message = "세부 설명 리스트는 null일 수 없습니다.") + List detailDescriptions, + + @NotNull(message = "세부 이미지 리스트는 null일 수 없습니다.") + List detailImages +) { + public List toRequest() { + validateListsSize(); + + List requests = new ArrayList<>(); + + requests.add(new FarmInfoRegisterRequest( + true, + title, + null, + mainImage + )); + + // Add detailed farm info requests + for (int i = 0; i < detailTitles.size(); i++) { + String detailTitle = detailTitles.get(i); + String detailDescription = (i < detailDescriptions.size()) ? detailDescriptions.get(i) : null; + String detailImage = (i < detailImages.size()) ? detailImages.get(i) : null; + + requests.add(new FarmInfoRegisterRequest( + false, + detailTitle, + detailDescription, + detailImage + )); + } + + return requests; + } + + private void validateListsSize() { + if (detailDescriptions.size() != detailTitles.size()) { + throw new BusinessException(FARM_INFO_DETAIL_SIZE_MISMATCH); + } + if (detailImages.size() != detailTitles.size()) { + throw new BusinessException(FARM_INFO_DETAIL_SIZE_MISMATCH); + } + } +} diff --git a/src/main/java/poomasi/domain/farm/dto/request/FarmInfoUpdateRequest.java b/src/main/java/poomasi/domain/farm/dto/request/FarmInfoUpdateRequest.java new file mode 100644 index 00000000..11641705 --- /dev/null +++ b/src/main/java/poomasi/domain/farm/dto/request/FarmInfoUpdateRequest.java @@ -0,0 +1,9 @@ +package poomasi.domain.farm.dto.request; + +public record FarmInfoUpdateRequest( + Long farmId, + String title, + String content, + String imageUrl +) { +} diff --git a/src/main/java/poomasi/domain/farm/dto/request/FarmRegisterRequest.java b/src/main/java/poomasi/domain/farm/dto/request/FarmRegisterRequest.java index d125215f..7b068021 100644 --- a/src/main/java/poomasi/domain/farm/dto/request/FarmRegisterRequest.java +++ b/src/main/java/poomasi/domain/farm/dto/request/FarmRegisterRequest.java @@ -1,8 +1,10 @@ package poomasi.domain.farm.dto.request; import jakarta.validation.constraints.NotNull; +import lombok.Builder; import poomasi.domain.farm.entity.Farm; +@Builder public record FarmRegisterRequest( @NotNull String name, @@ -30,7 +32,12 @@ public record FarmRegisterRequest( @NotNull String imageUrl, @NotNull - int price + int price, + + @NotNull + String businessNumber, + + FarmInfoAggregateRequest info ) { public Farm toEntity(Long memberId) { return Farm.builder() @@ -49,6 +56,7 @@ public Farm toEntity(Long memberId) { .mainImage(imageUrl) .growEnv(growEnv) .experiencePrice(price) + .businessNumber(businessNumber) .build(); } } diff --git a/src/main/java/poomasi/domain/farm/dto/response/FarmDetailResponse.java b/src/main/java/poomasi/domain/farm/dto/response/FarmDetailResponse.java index c7fe369f..c786ad73 100644 --- a/src/main/java/poomasi/domain/farm/dto/response/FarmDetailResponse.java +++ b/src/main/java/poomasi/domain/farm/dto/response/FarmDetailResponse.java @@ -2,12 +2,10 @@ import lombok.Builder; -import java.util.List; - @Builder public record FarmDetailResponse( FarmResponse farmResponse, - List experienceResponses + FarmInfoAggregateResponse info ) { diff --git a/src/main/java/poomasi/domain/farm/dto/response/FarmInfoAggregateResponse.java b/src/main/java/poomasi/domain/farm/dto/response/FarmInfoAggregateResponse.java new file mode 100644 index 00000000..e2a33e3d --- /dev/null +++ b/src/main/java/poomasi/domain/farm/dto/response/FarmInfoAggregateResponse.java @@ -0,0 +1,36 @@ +package poomasi.domain.farm.dto.response; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import poomasi.domain.farm.entity.FarmInfo; + +import java.util.List; + +public record FarmInfoAggregateResponse( + @NotBlank(message = "제목은 필수 입력값입니다.") + String title, + + @NotBlank(message = "대표 이미지는 필수 입력값입니다.") + String mainImage, + + @NotNull(message = "세부 제목 리스트는 null일 수 없습니다.") + @Size(min = 3, max = 3, message = "세부 제목은 3개여야 합니다.") + List detailTitles, + + @NotNull(message = "세부 설명 리스트는 null일 수 없습니다.") + List detailDescriptions, + + @NotNull(message = "세부 이미지 리스트는 null일 수 없습니다.") + List detailImages +) { + public static FarmInfoAggregateResponse fromEntity(List farmInfos) { + return new FarmInfoAggregateResponse( + farmInfos.get(0).getTitle(), + farmInfos.get(0).getImageUrl(), + List.of(farmInfos.get(1).getTitle(), farmInfos.get(2).getTitle(), farmInfos.get(3).getTitle()), + List.of(farmInfos.get(1).getContent(), farmInfos.get(2).getContent(), farmInfos.get(3).getContent()), + List.of(farmInfos.get(1).getImageUrl(), farmInfos.get(2).getImageUrl(), farmInfos.get(3).getImageUrl()) + ); + } +} diff --git a/src/main/java/poomasi/domain/farm/dto/response/FarmResponse.java b/src/main/java/poomasi/domain/farm/dto/response/FarmResponse.java index 881cec2c..bac395f3 100644 --- a/src/main/java/poomasi/domain/farm/dto/response/FarmResponse.java +++ b/src/main/java/poomasi/domain/farm/dto/response/FarmResponse.java @@ -1,8 +1,9 @@ package poomasi.domain.farm.dto.response; +import lombok.Builder; import poomasi.domain.farm.entity.Farm; - +@Builder public record FarmResponse( Long id, String name, @@ -16,16 +17,16 @@ public record FarmResponse( ) { public static FarmResponse fromEntity(Farm farm) { - return new FarmResponse( - farm.getId(), - farm.getName(), - farm.getAddress(), - farm.getAddressDetail(), - farm.getLatitude(), - farm.getLongitude(), - farm.getDescription(), - farm.getExperiencePrice(), - farm.getAverageRating() - ); + return FarmResponse + .builder() + .name(farm.getName()) + .address(farm.getAddress()) + .addressDetail(farm.getAddressDetail()) + .latitude(farm.getLatitude()) + .longitude(farm.getLongitude()) + .description(farm.getDescription()) + .experiencePrice(farm.getExperiencePrice()) + .averageRating(farm.getAverageRating()) + .build(); } } diff --git a/src/main/java/poomasi/domain/farm/entity/FarmInfo.java b/src/main/java/poomasi/domain/farm/entity/FarmInfo.java index 327bf0b9..08f676dd 100644 --- a/src/main/java/poomasi/domain/farm/entity/FarmInfo.java +++ b/src/main/java/poomasi/domain/farm/entity/FarmInfo.java @@ -7,6 +7,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.hibernate.annotations.*; +import poomasi.domain.farm.dto.request.FarmInfoUpdateRequest; import java.time.LocalDateTime; @@ -33,6 +34,7 @@ public class FarmInfo { String title; @Comment("설명") + @Column(nullable = true) String content; @Comment("메인 이미지 여부") @@ -64,4 +66,10 @@ public boolean hasContent() { return content != null && !content.isBlank() && !content.isEmpty() && title != null && !title.isBlank() && !title.isEmpty(); } + + public void update(FarmInfoUpdateRequest request) { + this.imageUrl = request.imageUrl(); + this.title = request.title(); + this.content = request.content(); + } } diff --git a/src/main/java/poomasi/domain/farm/service/FarmFarmerService.java b/src/main/java/poomasi/domain/farm/service/FarmFarmerService.java index 78085094..56a22c7a 100644 --- a/src/main/java/poomasi/domain/farm/service/FarmFarmerService.java +++ b/src/main/java/poomasi/domain/farm/service/FarmFarmerService.java @@ -2,7 +2,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import poomasi.domain.farm.dto.request.FarmInfoRegisterRequest; +import poomasi.domain.farm.dto.request.FarmInfoUpdateRequest; import poomasi.domain.farm.dto.request.FarmRegisterRequest; import poomasi.domain.farm.dto.request.FarmUpdateRequest; import poomasi.domain.farm.entity.Farm; @@ -12,35 +14,45 @@ import poomasi.global.error.BusinessException; import java.util.List; -import java.util.Objects; import static poomasi.global.error.BusinessError.*; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class FarmFarmerService { private final FarmRepository farmRepository; + private final FarmService farmService; private final FarmInfoService farmInfoService; private final int MAX_FARM_INFO_COUNT = 4; + @Transactional public Long registerFarm(Member member, FarmRegisterRequest request) { - farmRepository.getFarmByOwnerIdAndDeletedAtIsNull(member.getId()).ifPresent(farm -> { throw new BusinessException(FARM_ALREADY_EXISTS); }); - return farmRepository.save(request.toEntity(member.getId())).getId(); + Long id = farmRepository.save(request.toEntity(member.getId())).getId(); + + List farmInfoRegisterRequests = request.info().toRequest(); + farmInfoRegisterRequests.forEach(farmInfoRegisterRequest -> { + registerFarmInfo(member, farmInfoRegisterRequest); + }); + + return id; } - public Long registerFarmInfo(Member member, FarmInfoRegisterRequest request) { - Farm farm = getFarmByFarmerId(member.getId()); + + @Transactional + public void registerFarmInfo(Member member, FarmInfoRegisterRequest request) { + Farm farm = farmService.getFarmByFarmerId(member.getId()); List farmInfos = farmInfoService.getFarmInfoByFarmId(farm.getId()).stream() .filter(FarmInfo::isValid) .toList(); - if (farmInfos.size() >= MAX_FARM_INFO_COUNT) { + if (farmInfos.size() > MAX_FARM_INFO_COUNT) { throw new BusinessException(FARM_INFO_LIMIT_EXCEEDED); } @@ -50,11 +62,12 @@ public Long registerFarmInfo(Member member, FarmInfoRegisterRequest request) { throw new BusinessException(FARM_INFO_MAIN_REQUIRED); } - return farmInfoService.saveFarmInfo(request.toEntity(farm.getId())); + farmInfoService.saveFarmInfo(request.toEntity(farm.getId())); } + @Transactional public Long updateFarm(Long farmerId, FarmUpdateRequest request) { - Farm farm = getFarmByFarmerId(farmerId); + Farm farm = farmService.getFarmByFarmerId(farmerId); if (!farm.getOwnerId().equals(farmerId)) { throw new BusinessException(FARM_OWNER_MISMATCH); @@ -63,16 +76,9 @@ public Long updateFarm(Long farmerId, FarmUpdateRequest request) { return farmRepository.save(request.toEntity(farm)).getId(); } - public Farm getFarmByFarmerId(Long farmerId) { - return farmRepository.getFarmByOwnerIdAndDeletedAtIsNull(farmerId).orElseThrow(() -> new BusinessException(FARM_NOT_FOUND)); - } - - private Farm getFarmByFarmId(Long farmId) { - return farmRepository.findByIdAndDeletedAtIsNull(farmId).orElseThrow(() -> new BusinessException(FARM_NOT_FOUND)); - } public void updateFarmExpPrice(Long farmerId, Long farmId, int expPrice) { - Farm farm = this.getFarmByFarmId(farmId); + Farm farm = farmService.getFarmByFarmId(farmId); if (!farm.getOwnerId().equals(farmerId)) { throw new BusinessException(FARM_OWNER_MISMATCH); } @@ -80,7 +86,7 @@ public void updateFarmExpPrice(Long farmerId, Long farmId, int expPrice) { } public void updateFarmMaxCapacity(Long farmerId, Long farmId, Integer maxCapacity) { - Farm farm = this.getFarmByFarmId(farmId); + Farm farm = farmService.getFarmByFarmId(farmId); if (!farm.getOwnerId().equals(farmerId)) { throw new BusinessException(FARM_OWNER_MISMATCH); } @@ -88,7 +94,7 @@ public void updateFarmMaxCapacity(Long farmerId, Long farmId, Integer maxCapacit } public void updateFarmMaxReservation(Long farmerId, Long farmId, Integer maxReservation) { - Farm farm = this.getFarmByFarmId(farmId); + Farm farm = farmService.getFarmByFarmId(farmId); if (!farm.getOwnerId().equals(farmerId)) { throw new BusinessException(FARM_OWNER_MISMATCH); } @@ -96,10 +102,34 @@ public void updateFarmMaxReservation(Long farmerId, Long farmId, Integer maxRese } public void deleteFarm(Long farmerId, Long farmId) { - Farm farm = this.getFarmByFarmId(farmId); + Farm farm = farmService.getFarmByFarmId(farmId); + + // farm이 null인 경우 예외 발생 + if (farm == null) { + throw new BusinessException(FARM_NOT_FOUND); + } + if (!farm.getOwnerId().equals(farmerId)) { throw new BusinessException(FARM_OWNER_MISMATCH); } - farmRepository.delete(farm); + + if (farm.getDeletedAt() != null) { + throw new BusinessException(FARM_ALREADY_DELETED); + } + + farmService.delete(farm); + farmInfoService.deleteFarmInfo(farmId); + } + + public Long updateFarmInfo(Member member, FarmInfoUpdateRequest request) { + Farm farm = farmService.getFarmByFarmerId(member.getId()); + + if (!farm.getOwnerId().equals(member.getId())) { + throw new BusinessException(FARM_OWNER_MISMATCH); + } + + FarmInfo farmInfo = farmInfoService.getFarmInfo(request.farmId()); + farmInfo.update(request); + return farmInfoService.saveFarmInfo(farmInfo); } } diff --git a/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java b/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java index c505fb6e..dfed0453 100644 --- a/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java +++ b/src/main/java/poomasi/domain/farm/service/FarmPlatformService.java @@ -4,6 +4,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import poomasi.domain.farm.dto.response.FarmDetailResponse; +import poomasi.domain.farm.dto.response.FarmInfoAggregateResponse; import poomasi.domain.farm.dto.response.FarmInfoResponse; import poomasi.domain.farm.dto.response.FarmResponse; @@ -19,9 +20,7 @@ public class FarmPlatformService { public FarmDetailResponse getFarmDetailByFarmId(Long farmId) { return FarmDetailResponse.builder() .farmResponse(FarmResponse.fromEntity(farmService.getFarmByFarmId(farmId))) - .experienceResponses(farmInfoService.getFarmInfoByFarmId(farmId).stream() - .map(FarmInfoResponse::fromEntity) - .collect(Collectors.toList())) + .info(FarmInfoAggregateResponse.fromEntity(farmInfoService.getFarmInfoByFarmId(farmId))) .build(); } diff --git a/src/main/java/poomasi/domain/farm/service/FarmService.java b/src/main/java/poomasi/domain/farm/service/FarmService.java index ea808ec6..a911b40c 100644 --- a/src/main/java/poomasi/domain/farm/service/FarmService.java +++ b/src/main/java/poomasi/domain/farm/service/FarmService.java @@ -13,6 +13,8 @@ import java.util.List; import java.util.stream.Collectors; +import static poomasi.global.error.BusinessError.FARM_NOT_FOUND; + @Service @RequiredArgsConstructor public class FarmService { @@ -21,6 +23,7 @@ public class FarmService { public List getFarmListByOwnerId(Long farmerId) { return farmRepository.findAllByOwnerIdAndDeletedAtIsNull(farmerId); } + public Farm getValidFarmByFarmId(Long farmId) { Farm farm = getFarmByFarmId(farmId); if (farm.getStatus() != FarmStatus.OPEN) { @@ -29,6 +32,10 @@ public Farm getValidFarmByFarmId(Long farmId) { return farm; } + public Farm getFarmByFarmerId(Long farmerId) { + return farmRepository.getFarmByOwnerIdAndDeletedAtIsNull(farmerId).orElseThrow(() -> new BusinessException(FARM_NOT_FOUND)); + } + public Farm getFarmByFarmId(Long farmId) { return farmRepository.findByIdAndDeletedAtIsNull(farmId) .orElseThrow(() -> new BusinessException(BusinessError.FARM_NOT_FOUND)); @@ -38,4 +45,9 @@ public List getFarmList(Pageable pageable) { return farmRepository.findByDeletedAtIsNull(pageable).stream() .collect(Collectors.toList()); } + + public void delete(Farm farm) { + farm.delete(); + farmRepository.save(farm); + } } diff --git a/src/main/java/poomasi/domain/order/entity/_farm/FarmOrder.java b/src/main/java/poomasi/domain/order/entity/_farm/FarmOrder.java index c1b5fe68..9e9178f9 100644 --- a/src/main/java/poomasi/domain/order/entity/_farm/FarmOrder.java +++ b/src/main/java/poomasi/domain/order/entity/_farm/FarmOrder.java @@ -33,7 +33,7 @@ public class FarmOrder extends AbstractOrder { */ @Column(name = "merchant_uid") - @Description("서버 내부 주문 id(아임포트 id)") + @Description("서버 내부 주문 farmId(아임포트 farmId)") private String merchantUid = "f" + new Date().getTime(); diff --git a/src/main/java/poomasi/domain/order/entity/_farm/FarmOrderDetails.java b/src/main/java/poomasi/domain/order/entity/_farm/FarmOrderDetails.java index 7b6e194c..b7943b11 100644 --- a/src/main/java/poomasi/domain/order/entity/_farm/FarmOrderDetails.java +++ b/src/main/java/poomasi/domain/order/entity/_farm/FarmOrderDetails.java @@ -10,7 +10,7 @@ public class FarmOrderDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "farm_order_details_id") - private Long id; + private Long farmId; @OneToOne private FarmOrder farmOrder; diff --git a/src/main/java/poomasi/domain/order/service/ProductOrderService.java b/src/main/java/poomasi/domain/order/service/ProductOrderService.java index 101f8582..89928650 100644 --- a/src/main/java/poomasi/domain/order/service/ProductOrderService.java +++ b/src/main/java/poomasi/domain/order/service/ProductOrderService.java @@ -149,7 +149,7 @@ public List findAllOrdersByMemberId() { ); } - @Description("멤버 id 기반으로 특정 orderId 들고오는 메서드") + @Description("멤버 farmId 기반으로 특정 orderId 들고오는 메서드") public OrderResponse findOrderByMemberId(Long orderId) { Member member = getMember(); ProductOrder productOrder = productOrderRepository.findById(orderId) diff --git a/src/main/java/poomasi/domain/product/_intro/entity/ProductIntro.java b/src/main/java/poomasi/domain/product/_intro/entity/ProductIntro.java index 691c3489..3c5c46ff 100644 --- a/src/main/java/poomasi/domain/product/_intro/entity/ProductIntro.java +++ b/src/main/java/poomasi/domain/product/_intro/entity/ProductIntro.java @@ -25,7 +25,7 @@ public class ProductIntro { private Long id; @OneToOne - @JoinColumn(name = "id") + @JoinColumn(name = "farmId") @Setter private Product product; diff --git a/src/main/java/poomasi/domain/product/entity/Product.java b/src/main/java/poomasi/domain/product/entity/Product.java index fa5c1c2c..00bcd98a 100644 --- a/src/main/java/poomasi/domain/product/entity/Product.java +++ b/src/main/java/poomasi/domain/product/entity/Product.java @@ -23,7 +23,7 @@ @Entity @Getter @NoArgsConstructor -//@SQLDelete(sql = "UPDATE product SET deleted_at = current_timestamp WHERE id = ?") +//@SQLDelete(sql = "UPDATE product SET deleted_at = current_timestamp WHERE farmId = ?") public class Product { @Id diff --git a/src/main/java/poomasi/domain/store/repository/StoreRepository.java b/src/main/java/poomasi/domain/store/repository/StoreRepository.java index 397b1b58..4cbb16f8 100644 --- a/src/main/java/poomasi/domain/store/repository/StoreRepository.java +++ b/src/main/java/poomasi/domain/store/repository/StoreRepository.java @@ -8,6 +8,6 @@ @Repository public interface StoreRepository extends JpaRepository { - //@Query("select s from Store s where s.owner.id = :id") + //@Query("select s from Store s where s.owner.farmId = :farmId") Optional findByOwnerId(Long id); } diff --git a/src/main/java/poomasi/global/error/BusinessError.java b/src/main/java/poomasi/global/error/BusinessError.java index 5097ef70..dc327455 100644 --- a/src/main/java/poomasi/global/error/BusinessError.java +++ b/src/main/java/poomasi/global/error/BusinessError.java @@ -45,6 +45,7 @@ public enum BusinessError { FARM_OWNER_MISMATCH(HttpStatus.FORBIDDEN, "해당 농장의 소유자가 아닙니다."), FARM_ALREADY_EXISTS(HttpStatus.CONFLICT, "이미 농장이 존재합니다."), FARM_NOT_OPEN(HttpStatus.BAD_REQUEST, "오픈되지 않은 농장입니다."), + FARM_ALREADY_DELETED(HttpStatus.BAD_REQUEST, "이미 삭제된 농장입니다."), // FarmInfo FARM_INFO_LIMIT_EXCEEDED(HttpStatus.BAD_REQUEST, "농장 소개는 최대 3개까지 등록 가능합니다."), @@ -52,6 +53,8 @@ public enum BusinessError { FARM_INFO_MAIN_REQUIRED(HttpStatus.BAD_REQUEST, "메인 소개가 필요합니다."), FARM_INFO_MAIN_REQUIRED_NO_CONTENT(HttpStatus.BAD_REQUEST, "메인 소개가 필요합니다."), FARM_INFO_NON_MAIN_REQUIRED_CONTENT(HttpStatus.BAD_REQUEST, "메인이 아닌 이미지는 내용이 필요합니다."), + FARM_INFO_NOT_VALID(HttpStatus.BAD_REQUEST, "농장 소개가 유효하지 않습니다."), + FARM_INFO_DETAIL_SIZE_MISMATCH(HttpStatus.BAD_REQUEST, "세부 소개의 크기가 일치하지 않습니다."), // FarmSchedule FARM_SCHEDULE_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 날짜의 스케줄을 찾을 수 없습니다."), diff --git a/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java b/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java index eb47b14a..b35d41fb 100644 --- a/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java +++ b/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java @@ -7,6 +7,7 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import poomasi.domain.farm.FarmTestHelper; import poomasi.domain.farm.dto.request.FarmRegisterRequest; import poomasi.domain.farm.entity.Farm; import poomasi.domain.farm.repository.FarmRepository; @@ -14,10 +15,12 @@ import poomasi.global.error.BusinessError; import poomasi.global.error.BusinessException; +import java.time.LocalDateTime; import java.util.Optional; import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) @@ -25,10 +28,14 @@ class FarmFarmerServiceTest { @InjectMocks private FarmFarmerService farmFarmerService; - + @Mock + private FarmInfoService farmInfoService; + @Mock + private FarmService farmService; @Mock private FarmRepository farmRepository; + @Nested @DisplayName("농장 등록") class RegisterFarm { @@ -47,7 +54,21 @@ void should_throwException_when_farmAlreadyExists() { given(farmRepository.getFarmByOwnerIdAndDeletedAtIsNull(member.getId())).willReturn(Optional.of(existingFarm)); - FarmRegisterRequest request = new FarmRegisterRequest("New Farm", "Address", "Detail", "010-1234-5678", 1.0, 1.0, "010-123-123", "10000", 10, 10, 10, 1L, "10", 10); + FarmRegisterRequest request = FarmRegisterRequest + .builder() + .name("New Farm") + .address("Address") + .addressDetail("Detail") + .phoneNumber("010-1234-5678") + .latitude(1.0) + .longitude(1.0) + .phoneNumber("010-123-123") + .experiencePrice(10000) + .maxPeople(10) + .maxTeam(10) + .categoryId(1L) + .imageUrl("10") + .price(10).build(); // when & then assertThatThrownBy(() -> farmFarmerService.registerFarm(member, request)) @@ -71,7 +92,7 @@ void should_throwException_when_ownerMismatchOnDelete() { .name("Farm") .ownerId(3L) .build(); - given(farmRepository.findByIdAndDeletedAtIsNull(farmId)).willReturn(Optional.of(farm)); + given(farmService.getFarmByFarmId(farmId)).willReturn(farm); // when & then assertThatThrownBy(() -> farmFarmerService.deleteFarm(farmerId, farmId)) @@ -90,22 +111,26 @@ void should_deleteFarm_when_ownerMatches() { .name("Farm") .ownerId(farmerId) .build(); - given(farmRepository.findByIdAndDeletedAtIsNull(farmId)).willReturn(Optional.of(farm)); + + given(farmService.getFarmByFarmId(farmId)).willReturn(farm); // when farmFarmerService.deleteFarm(farmerId, farmId); // then - verify(farmRepository).delete(farm); + verify(farmService).delete(farm); + verify(farmInfoService).deleteFarmInfo(farmId); } @Test @DisplayName("농장이 존재하지 않는 경우 예외를 발생시킨다") void should_throwException_when_farmNotExistOnDelete() { // given - Long farmId = 1L; + Long farmId = 3L; Long farmerId = 1L; - given(farmRepository.findByIdAndDeletedAtIsNull(farmId)).willReturn(Optional.empty()); + + // farmService에서 농장이 없을 때 null을 반환하도록 설정 + given(farmService.getFarmByFarmId(farmId)).willReturn(null); // when & then assertThatThrownBy(() -> farmFarmerService.deleteFarm(farmerId, farmId)) @@ -123,16 +148,19 @@ void should_throwException_when_farmAlreadyDeleted() { .id(farmId) .name("Farm") .ownerId(farmerId) - .deletedAt(null) + .deletedAt(LocalDateTime.now()) // 이미 삭제된 상태 .build(); - given(farmRepository.findByIdAndDeletedAtIsNull(farmId)).willReturn(Optional.of(farm)); + given(farmService.getFarmByFarmId(farmId)).willReturn(farm); - // when - farmFarmerService.deleteFarm(farmerId, farmId); + // when & then + assertThatThrownBy(() -> farmFarmerService.deleteFarm(farmerId, farmId)) + .isInstanceOf(BusinessException.class) + .hasFieldOrPropertyWithValue("businessError", BusinessError.FARM_ALREADY_DELETED); - // then - verify(farmRepository).delete(farm); + // delete 메서드가 호출되지 않았는지 확인 + verify(farmService, never()).delete(farm); + verify(farmInfoService, never()).deleteFarmInfo(farmId); } } } diff --git a/src/test/java/poomasi/domain/farm/service/FarmPlatformServiceTest.java b/src/test/java/poomasi/domain/farm/service/FarmPlatformServiceTest.java index f0f3ffa4..35ccc0ac 100644 --- a/src/test/java/poomasi/domain/farm/service/FarmPlatformServiceTest.java +++ b/src/test/java/poomasi/domain/farm/service/FarmPlatformServiceTest.java @@ -42,16 +42,26 @@ void should_returnFarmResponse_when_farmExists() { .id(farmId) .name("Test Farm") .ownerId(1L) + .experiencePrice(10000) + .address("Address") + .phoneNumber("010-1234-5678") + .latitude(1.0) + .longitude(1.0) + .mainImage("Main Image") + .description("Description") + .growEnv("Grow Env") + .maxCapacity(10) + .maxReservation(5) + .categoryId(1L) .build(); + given(farmService.getFarmByFarmId(farmId)).willReturn(farm); // when FarmResponse response = farmPlatformService.getFarmByFarmId(farmId); // then - assertThat(response.id()).isEqualTo(farmId); assertThat(response.name()).isEqualTo("Test Farm"); - verify(farmService).getFarmByFarmId(farmId); // farmService 호출 확인 } @Test