diff --git a/src/main/java/poomasi/domain/auth/signup/service/SignupService.java b/src/main/java/poomasi/domain/auth/signup/service/SignupService.java new file mode 100644 index 00000000..7099ec8b --- /dev/null +++ b/src/main/java/poomasi/domain/auth/signup/service/SignupService.java @@ -0,0 +1,47 @@ +package poomasi.domain.auth.signup.service; + +import jdk.jfr.Description; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import poomasi.domain.member.dto.request.SignupRequest; +import poomasi.domain.member.dto.response.SignUpResponse; +import poomasi.domain.member.entity.LoginType; +import poomasi.domain.member.repository.MemberRepository; +import poomasi.domain.member.entity.Member; +import poomasi.global.error.BusinessException; + +import static poomasi.domain.member.entity.Role.ROLE_CUSTOMER; +import static poomasi.domain.member.entity.Role.ROLE_FARMER; +import static poomasi.global.error.BusinessError.*; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class SignupService { + + private final MemberRepository memberRepository; + private final PasswordEncoder passwordEncoder; + + @Description("카카오톡으로 먼저 회원가입이 되어 있는 경우, 계정 연동을 진행합니다. ") + @Transactional + public SignUpResponse signUp(SignupRequest signupRequest) { + String email = signupRequest.email(); + String password = signupRequest.password(); + + memberRepository.findByEmail(email) + .ifPresent(member -> { throw new BusinessException(DUPLICATE_MEMBER_EMAIL); }); + + Member newMember = Member.builder() + .email(email) + .password(passwordEncoder.encode(password)) + .loginType(LoginType.LOCAL) + .role(ROLE_FARMER) + .build(); + memberRepository.save(newMember); + return new SignUpResponse(email, "회원 가입 성공"); + } +} + diff --git a/src/main/java/poomasi/domain/member/entity/Member.java b/src/main/java/poomasi/domain/member/entity/Member.java index 4dc7828b..fa2e8759 100644 --- a/src/main/java/poomasi/domain/member/entity/Member.java +++ b/src/main/java/poomasi/domain/member/entity/Member.java @@ -1,17 +1,19 @@ package poomasi.domain.member.entity; import jakarta.persistence.*; +import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.hibernate.annotations.SQLDelete; import poomasi.domain.order.entity.Order; +import poomasi.domain.store.entity.Store; import poomasi.domain.member._profile.entity.MemberProfile; import poomasi.domain.wishlist.entity.WishList; - -import java.time.LocalDateTime; -import java.util.List; +import poomasi.global.error.BusinessError; +import poomasi.global.error.BusinessException; +import java.util.*; @Getter @Entity @@ -49,7 +51,7 @@ public class Member { @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List<WishList> wishLists; - @Column(name="deleted_at") + @Column(name = "deleted_at") private LocalDateTime deletedAt; @OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true) @@ -59,6 +61,10 @@ public class Member { @Column(nullable = true) private String farmerTierCode; + @Setter + @OneToOne(mappedBy="owner", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + Store store; + public Member(String email, String password, LoginType loginType, Role role) { this.email = email; this.password = password; @@ -79,8 +85,9 @@ public void setMemberProfile(MemberProfile memberProfile) { } @Builder - public Member(Long id, String email, Role role, LoginType loginType, String provideId, MemberProfile memberProfile) { + public Member(Long id, String email, String password, Role role, LoginType loginType, String provideId, MemberProfile memberProfile) { this.id = id; + this.password = password; this.email = email; this.role = role; this.loginType = loginType; @@ -99,4 +106,11 @@ public boolean isFarmer() { public boolean isAdmin() { return role == Role.ROLE_ADMIN; } + + public Store getStore() { + if(store == null) + throw new BusinessException(BusinessError.STORE_NOT_FOUND); + return store; + } + } 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 bf474106..7a50b0bb 100644 --- a/src/main/java/poomasi/domain/product/_cart/entity/Cart.java +++ b/src/main/java/poomasi/domain/product/_cart/entity/Cart.java @@ -26,7 +26,8 @@ public class Cart { private Integer count; @Builder - public Cart(Long memberId, Long productId, Boolean selected, Integer count) { + public Cart(Long id, Long memberId, Long productId, Boolean selected, Integer count) { + this.id = id; this.memberId = memberId; this.productId = productId; this.selected = selected; diff --git a/src/main/java/poomasi/domain/product/_category/entity/Category.java b/src/main/java/poomasi/domain/product/_category/entity/Category.java index b1957cdb..2e5e2b78 100644 --- a/src/main/java/poomasi/domain/product/_category/entity/Category.java +++ b/src/main/java/poomasi/domain/product/_category/entity/Category.java @@ -9,6 +9,7 @@ import jakarta.persistence.OneToMany; import java.util.ArrayList; import java.util.List; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import poomasi.domain.product._category.dto.CategoryRequest; @@ -28,6 +29,13 @@ public class Category { @JoinColumn(name = "categoryId") List<Product> products = new ArrayList<>(); + @Builder + public Category(Long id, String name) { + this.id = id; + this.name = name; + this.products = new ArrayList<>(); + } + public Category(String name) { this.name = name; } diff --git a/src/main/java/poomasi/domain/product/dto/ProductRegisterRequest.java b/src/main/java/poomasi/domain/product/dto/ProductRegisterRequest.java index 57828406..ffbae25b 100644 --- a/src/main/java/poomasi/domain/product/dto/ProductRegisterRequest.java +++ b/src/main/java/poomasi/domain/product/dto/ProductRegisterRequest.java @@ -1,6 +1,7 @@ package poomasi.domain.product.dto; import poomasi.domain.member.entity.Member; +import poomasi.domain.store.entity.Store; import poomasi.domain.product.entity.Product; public record ProductRegisterRequest( @@ -12,7 +13,7 @@ public record ProductRegisterRequest( Long price ) { - public Product toEntity(Member member) { + public Product toEntity(Member member, Store store) { return Product.builder() .categoryId(categoryId) .farmerId(member.getId()) @@ -22,6 +23,7 @@ public Product toEntity(Member member) { .imageUrl(imageUrl) .stock(stock) .price(price) + .store(store) .build(); } } diff --git a/src/main/java/poomasi/domain/product/dto/ProductResponse.java b/src/main/java/poomasi/domain/product/dto/ProductResponse.java index 6975a2a7..a759c3f4 100644 --- a/src/main/java/poomasi/domain/product/dto/ProductResponse.java +++ b/src/main/java/poomasi/domain/product/dto/ProductResponse.java @@ -14,6 +14,7 @@ public record ProductResponse( String description, String imageUrl, Long categoryId, + String storeName, List<String> tags ) { @@ -27,6 +28,7 @@ public static ProductResponse fromEntity(Product product) { .stock(product.getStock()) .description(product.getDescription()) .imageUrl(product.getImageUrl()) + .storeName(product.getStore().getName()) .categoryId(product.getCategoryId()) .tags(tags) .build(); diff --git a/src/main/java/poomasi/domain/product/entity/Product.java b/src/main/java/poomasi/domain/product/entity/Product.java index 8c171d6a..8c70ba51 100644 --- a/src/main/java/poomasi/domain/product/entity/Product.java +++ b/src/main/java/poomasi/domain/product/entity/Product.java @@ -12,6 +12,7 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import java.time.LocalDateTime; import java.util.ArrayList; @@ -21,9 +22,9 @@ import lombok.NoArgsConstructor; import org.hibernate.annotations.Comment; import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.UpdateTimestamp; import poomasi.domain.order.entity.OrderProductDetails; +import poomasi.domain.store.entity.Store; import poomasi.domain.product.dto.ProductRegisterRequest; import poomasi.domain.review.entity.Review; @@ -71,6 +72,10 @@ public class Product { @JoinColumn(name = "entityId") List<Review> reviewList = new ArrayList<>(); + @ManyToOne + @JoinColumn(name = "store_id") // 외래 키 컬럼 지정 + private Store store; + @ElementCollection(fetch = FetchType.LAZY) @CollectionTable(name = "product_tag", joinColumns = @JoinColumn(name = "product_id")) @Column(name = "enum_value") @@ -93,7 +98,9 @@ public Product(Long productId, String description, String imageUrl, Integer stock, - Long price) { + Long price, + Store store) { + this.id = productId; this.categoryId = categoryId; this.farmerId = farmerId; this.name = name; @@ -101,6 +108,7 @@ public Product(Long productId, this.imageUrl = imageUrl; this.stock = stock; this.price = price; + this.store = store; } public Product modify(ProductRegisterRequest productRegisterRequest) { @@ -117,14 +125,4 @@ public void addStock(Integer stock) { this.stock += stock; } - public void addReview(Review pReview) { - this.reviewList.add(pReview); - this.averageRating = reviewList.stream() - .mapToDouble(Review::getRating) // 각 리뷰의 평점을 double로 변환 - .average() // 평균 계산 - .orElse(0.0); - } - - - } diff --git a/src/main/java/poomasi/domain/product/service/ProductFarmerService.java b/src/main/java/poomasi/domain/product/service/ProductFarmerService.java index a225cfb7..52140d85 100644 --- a/src/main/java/poomasi/domain/product/service/ProductFarmerService.java +++ b/src/main/java/poomasi/domain/product/service/ProductFarmerService.java @@ -6,6 +6,8 @@ import poomasi.domain.member.entity.Member; import poomasi.domain.product._category.entity.Category; import poomasi.domain.product._category.repository.CategoryRepository; +import poomasi.domain.store.entity.Store; +import poomasi.domain.store.repository.StoreRepository; import poomasi.domain.product.dto.ProductRegisterRequest; import poomasi.domain.product.dto.UpdateProductQuantityRequest; import poomasi.domain.product.entity.Product; @@ -19,12 +21,16 @@ public class ProductFarmerService { private final ProductRepository productRepository; private final CategoryRepository categoryRepository; + private final StoreRepository storeRepository; @Transactional public Long registerProduct(Member member, ProductRegisterRequest request) { Category category = getCategory(request.categoryId()); - Product saveProduct = productRepository.save(request.toEntity(member)); + Store store = member.getStore(); + Product saveProduct = productRepository.save(request.toEntity(member,store)); + category.addProduct(saveProduct); + store.addProduct(saveProduct); return saveProduct.getId(); } @@ -47,7 +53,6 @@ public void modifyProduct(Member member, ProductRegisterRequest productRequest, @Transactional public void deleteProduct(Member member, Long productId) { - //TODO: 주인인지 알아보기 Product product = getProductByProductId(productId); checkAuth(member, product); diff --git a/src/main/java/poomasi/domain/review/dto/ReviewResponse.java b/src/main/java/poomasi/domain/review/dto/ReviewResponse.java index ba6d42b0..52524f66 100644 --- a/src/main/java/poomasi/domain/review/dto/ReviewResponse.java +++ b/src/main/java/poomasi/domain/review/dto/ReviewResponse.java @@ -15,7 +15,7 @@ public static ReviewResponse fromEntity(Review review) { return new ReviewResponse( review.getId(), review.getEntityId(), - review.getReviewer().getMemberProfile().getName(), + review.getReviewer().getMemberProfile()==null?"":review.getReviewer().getMemberProfile().getName(), review.getRating(), review.getContent() ); diff --git a/src/main/java/poomasi/domain/review/entity/Review.java b/src/main/java/poomasi/domain/review/entity/Review.java index 9eda7960..dda0c932 100644 --- a/src/main/java/poomasi/domain/review/entity/Review.java +++ b/src/main/java/poomasi/domain/review/entity/Review.java @@ -51,8 +51,9 @@ public class Review { private Member reviewer; @Builder - public Review(Float rating, String content, Long entityId, EntityType entityType, + public Review(Long id, Float rating, String content, Long entityId, EntityType entityType, Member reviewer) { + this.id = id; this.rating = rating; this.content = content; this.entityId = entityId; diff --git a/src/main/java/poomasi/domain/store/controller/StoreController.java b/src/main/java/poomasi/domain/store/controller/StoreController.java new file mode 100644 index 00000000..5101e889 --- /dev/null +++ b/src/main/java/poomasi/domain/store/controller/StoreController.java @@ -0,0 +1,41 @@ +package poomasi.domain.store.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.annotation.Secured; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import poomasi.domain.store.dto.StoreRegisterRequest; +import poomasi.domain.store.service.StoreService; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/api/store") +public class StoreController { + + private final StoreService storeService; + + @Secured("ROLE_FARMER") + @PostMapping("") + public ResponseEntity<?> addStore(@RequestBody StoreRegisterRequest storeRegisterRequest) { + storeService.addStore(storeRegisterRequest); + return ResponseEntity.ok().build(); + } + + @Secured("ROLE_FARMER") + @GetMapping("") + public ResponseEntity<?> getStore() { + return ResponseEntity.ok(storeService.getStore()); + } + + @Secured("ROLE_FARMER") + @PutMapping("") + public ResponseEntity<?> updateStore(@RequestBody StoreRegisterRequest storeRegisterRequest) { + storeService.updateStore(storeRegisterRequest); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/poomasi/domain/store/dto/StoreFeeRequest.java b/src/main/java/poomasi/domain/store/dto/StoreFeeRequest.java new file mode 100644 index 00000000..57d332cd --- /dev/null +++ b/src/main/java/poomasi/domain/store/dto/StoreFeeRequest.java @@ -0,0 +1,7 @@ +package poomasi.domain.store.dto; + +public record StoreFeeRequest( + Integer fee +) { + +} diff --git a/src/main/java/poomasi/domain/store/dto/StoreRegisterRequest.java b/src/main/java/poomasi/domain/store/dto/StoreRegisterRequest.java new file mode 100644 index 00000000..08e975d3 --- /dev/null +++ b/src/main/java/poomasi/domain/store/dto/StoreRegisterRequest.java @@ -0,0 +1,29 @@ +package poomasi.domain.store.dto; + +import org.hibernate.annotations.Comment; +import poomasi.domain.member.entity.Member; +import poomasi.domain.store.entity.Store; + +public record StoreRegisterRequest( + String name, + String address, + String phone, + String ownerPhone, + @Comment("사업자 번호") + String businessNumber, + @Comment("배송비") + Integer shipingFee +) { + + public Store toEntity(Member member) { + return Store.builder() + .name(name) + .address(address) + .phone(phone) + .ownerPhone(ownerPhone) + .businessNumber(businessNumber) + .shipingFee(shipingFee) + .owner(member) + .build(); + } +} diff --git a/src/main/java/poomasi/domain/store/dto/StoreResponse.java b/src/main/java/poomasi/domain/store/dto/StoreResponse.java new file mode 100644 index 00000000..cb99e0c7 --- /dev/null +++ b/src/main/java/poomasi/domain/store/dto/StoreResponse.java @@ -0,0 +1,54 @@ +package poomasi.domain.store.dto; + +import jakarta.validation.constraints.Positive; +import java.util.List; +import lombok.Builder; +import org.hibernate.annotations.Comment; +import org.jetbrains.annotations.NotNull; +import poomasi.domain.store.entity.Store; +import poomasi.domain.product.dto.ProductResponse; + +@Builder +public record StoreResponse( + @NotNull + String name, + + @NotNull + String address, + + String phone, + + @NotNull + String ownerPhone, + + @Comment("사업자 번호") + @NotNull + String businessNumber, + + @Comment("배송비") + @NotNull + @Positive + Integer shipingFee, + + @NotNull + String ownerName, + + List<ProductResponse> products +) { + + public static StoreResponse fromEntity(Store store) { + return StoreResponse.builder() + .name(store.getName()) + .address(store.getAddress()) + .phone(store.getPhone()) + .ownerPhone(store.getOwnerPhone()) + .businessNumber(store.getBusinessNumber()) + .shipingFee(store.getShipingFee()) + //TODO 나중에 삼항연산자 삭제 + .ownerName( store.getOwner().getMemberProfile() == null ? "" + : store.getOwner().getMemberProfile().getName()) + .products(store.getProducts().stream().map(ProductResponse::fromEntity).toList()) + .build(); + + } +} \ No newline at end of file diff --git a/src/main/java/poomasi/domain/store/entity/Store.java b/src/main/java/poomasi/domain/store/entity/Store.java new file mode 100644 index 00000000..c4be3f96 --- /dev/null +++ b/src/main/java/poomasi/domain/store/entity/Store.java @@ -0,0 +1,70 @@ +package poomasi.domain.store.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import java.util.ArrayList; +import java.util.List; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Comment; +import poomasi.domain.member.entity.Member; +import poomasi.domain.store.dto.StoreRegisterRequest; +import poomasi.domain.product.entity.Product; + +@Entity +@NoArgsConstructor +@Getter +public class Store { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + private String address; + private String phone; + + @OneToOne(fetch = FetchType.LAZY) + private Member owner; + + private String ownerPhone; + @Comment("사업자 번호") + private String businessNumber; + @Comment("배송비") + private Integer shipingFee; + + @OneToMany(mappedBy = "store", cascade = CascadeType.ALL) + List<Product> products = new ArrayList<>(); + + @Builder + public Store(Long id, String name, String address, String phone, Member owner, + String ownerPhone, String businessNumber, Integer shipingFee) { + this.id = id; + this.name = name; + this.address = address; + this.phone = phone; + this.owner = owner; + this.ownerPhone = ownerPhone; + this.businessNumber = businessNumber; + this.shipingFee = shipingFee; + } + + public void updateStore(StoreRegisterRequest storeRegisterRequest) { + this.name = storeRegisterRequest.name(); + this.address = storeRegisterRequest.address(); + this.phone = storeRegisterRequest.phone(); + this.ownerPhone = storeRegisterRequest.ownerPhone(); + this.businessNumber = storeRegisterRequest.businessNumber(); + this.shipingFee = storeRegisterRequest.shipingFee(); + } + + public void addProduct(Product saveProduct) { + this.products.add(saveProduct); + } +} diff --git a/src/main/java/poomasi/domain/store/repository/StoreRepository.java b/src/main/java/poomasi/domain/store/repository/StoreRepository.java new file mode 100644 index 00000000..397b1b58 --- /dev/null +++ b/src/main/java/poomasi/domain/store/repository/StoreRepository.java @@ -0,0 +1,13 @@ +package poomasi.domain.store.repository; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import poomasi.domain.store.entity.Store; + +@Repository +public interface StoreRepository extends JpaRepository<Store, Long> { + + //@Query("select s from Store s where s.owner.id = :id") + Optional<Store> findByOwnerId(Long id); +} diff --git a/src/main/java/poomasi/domain/store/service/StoreService.java b/src/main/java/poomasi/domain/store/service/StoreService.java new file mode 100644 index 00000000..5920f908 --- /dev/null +++ b/src/main/java/poomasi/domain/store/service/StoreService.java @@ -0,0 +1,56 @@ +package poomasi.domain.store.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import poomasi.domain.auth.security.userdetail.UserDetailsImpl; +import poomasi.domain.member.entity.Member; +import poomasi.domain.store.dto.StoreRegisterRequest; +import poomasi.domain.store.dto.StoreResponse; +import poomasi.domain.store.entity.Store; +import poomasi.domain.store.repository.StoreRepository; +import poomasi.global.error.BusinessError; +import poomasi.global.error.BusinessException; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class StoreService { + + private final StoreRepository storeRepository; + + @Transactional + public void addStore(StoreRegisterRequest storeRegisterRequest) { + Member member = getMember(); + Store store = storeRegisterRequest.toEntity(member); + member.setStore(store); + storeRepository.save(store); + } + + public StoreResponse getStore() { + Member member = getMember(); + Store store = getStore(member); + return StoreResponse.fromEntity(store); + } + + private Store getStore(Member member) { + return storeRepository.findByOwnerId(member.getId()) + .orElseThrow(() -> new BusinessException(BusinessError.STORE_NOT_FOUND)); + } + + private Member getMember() { + Authentication authentication = SecurityContextHolder + .getContext().getAuthentication(); + Object impl = authentication.getPrincipal(); + return ((UserDetailsImpl) impl).getMember(); + } + + @Transactional + public void updateStore(StoreRegisterRequest storeRegisterRequest) { + Member member = getMember(); + Store store = getStore(member); + store.updateStore(storeRegisterRequest); + } +} diff --git a/src/main/java/poomasi/global/error/BusinessError.java b/src/main/java/poomasi/global/error/BusinessError.java index 653b6b97..67d668d4 100644 --- a/src/main/java/poomasi/global/error/BusinessError.java +++ b/src/main/java/poomasi/global/error/BusinessError.java @@ -84,7 +84,10 @@ public enum BusinessError { // PAYMENT PAYMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "결제를 찾을 수 없습니다."), - PAYMENT_AMOUNT_MISMATCH(HttpStatus.BAD_REQUEST, "사전 결제 금액과 사후 결제 금액이 일치하지 않습니다."); + PAYMENT_AMOUNT_MISMATCH(HttpStatus.BAD_REQUEST, "사전 결제 금액과 사후 결제 금액이 일치하지 않습니다."), + + //Store + STORE_NOT_FOUND(HttpStatus.NOT_FOUND, "등록된 상점이 없습니다."); private final HttpStatus httpStatus; diff --git a/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java b/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java index c34ca6f8..3fc65918 100644 --- a/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java +++ b/src/test/java/poomasi/domain/farm/service/FarmFarmerServiceTest.java @@ -48,7 +48,7 @@ void should_throwException_when_farmAlreadyExists() { given(farmRepository.getFarmByOwnerIdAndDeletedAtIsNull(member.getId())).willReturn(Optional.of(existingFarm)); - FarmRegisterRequest request = new FarmRegisterRequest("New Farm", "Address", "Detail", 1.0, 1.0, "010-1234-5678", "Description", 10000L, 10, 5); + FarmRegisterRequest request = new FarmRegisterRequest("New Farm", "Address", "Detail", 1.0, 1.0, "010-1234-5678", "Description", 10000, 10, 5); // when & then assertThatThrownBy(() -> farmFarmerService.registerFarm(member, request)) diff --git a/src/test/java/poomasi/domain/store/StoreServiceTest.java b/src/test/java/poomasi/domain/store/StoreServiceTest.java new file mode 100644 index 00000000..c1327a03 --- /dev/null +++ b/src/test/java/poomasi/domain/store/StoreServiceTest.java @@ -0,0 +1,110 @@ +package poomasi.domain.store; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import java.util.Optional; +import poomasi.domain.auth.security.userdetail.UserDetailsImpl; +import poomasi.domain.member.entity.Member; +import poomasi.domain.store.dto.StoreRegisterRequest; +import poomasi.domain.store.dto.StoreResponse; +import poomasi.domain.store.entity.Store; +import poomasi.domain.store.repository.StoreRepository; +import poomasi.domain.store.service.StoreService; +import poomasi.global.error.BusinessError; +import poomasi.global.error.BusinessException; + +@ExtendWith(MockitoExtension.class) +class StoreServiceTest { + + @InjectMocks + private StoreService storeService; + + @Mock + private StoreRepository storeRepository; + + @Mock + private SecurityContext securityContext; + + @Mock + private Authentication authentication; + + private Member testMember; + + @BeforeEach + void setUp() { + // 테스트 멤버와 Authentication 설정 + testMember = Member.builder().build(); + + SecurityContextHolder.setContext(securityContext); + when(securityContext.getAuthentication()).thenReturn(authentication); + when(authentication.getPrincipal()).thenReturn(new UserDetailsImpl(testMember)); + } + + @Test + void addStore_StoreAddedSuccessfully() { + // given + StoreRegisterRequest request = mock(StoreRegisterRequest.class); + Store store = mock(Store.class); + + when(request.toEntity(any(Member.class))).thenReturn(store); + + // when + storeService.addStore(request); + + // then + verify(storeRepository, times(1)).save(store); + } + + @Test + void getStore_StoreExists_ReturnStoreResponse() { + // given + Store store = new Store(1L, "test","test","test",testMember,"test","test",100); + when(storeRepository.findByOwnerId(testMember.getId())).thenReturn(Optional.of(store)); + + // when + StoreResponse response = storeService.getStore(); + + // then + assertNotNull(response); + verify(storeRepository, times(1)).findByOwnerId(testMember.getId()); + } + + @Test + void updateStore_StoreExists_StoreUpdatedSuccessfully() { + // given + StoreRegisterRequest request = mock(StoreRegisterRequest.class); + Store store = mock(Store.class); + + when(storeRepository.findByOwnerId(testMember.getId())).thenReturn(Optional.of(store)); + + // when + storeService.updateStore(request); + + // then + verify(store, times(1)).updateStore(request); + } + + @Test + void updateStore_StoreDoesNotExist_ThrowsBusinessException() { + // given + StoreRegisterRequest request = mock(StoreRegisterRequest.class); + when(storeRepository.findByOwnerId(testMember.getId())).thenReturn(Optional.empty()); + + // when & then + BusinessException exception = assertThrows(BusinessException.class, () -> storeService.updateStore(request)); + assertEquals(BusinessError.STORE_NOT_FOUND, exception.getBusinessError()); + } + +} \ No newline at end of file