diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/StoreController.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/StoreController.java index 55efdee3..765248b6 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/StoreController.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/StoreController.java @@ -1,6 +1,5 @@ package sosteam.throwapi.domain.store.controller; -import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -13,15 +12,10 @@ import sosteam.throwapi.domain.store.entity.dto.StoreDto; import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; import sosteam.throwapi.domain.store.entity.dto.StoreSaveDto; -import sosteam.throwapi.domain.store.exception.BiznoAPIException; -import sosteam.throwapi.domain.store.exception.NoSuchRegistrationNumberException; -import sosteam.throwapi.domain.store.exception.NoSuchStoreException; -import sosteam.throwapi.domain.store.externalAPI.bizno.BiznoAPI; -import sosteam.throwapi.domain.store.externalAPI.bizno.BiznoApiResponse; -import sosteam.throwapi.domain.store.service.StoreCreateService; -import sosteam.throwapi.domain.store.service.StoreDeleteService; -import sosteam.throwapi.domain.store.service.StoreSearchService; -import sosteam.throwapi.domain.store.service.StoreModifyService; +import sosteam.throwapi.domain.store.service.*; +import sosteam.throwapi.domain.user.entity.dto.user.UserInfoDto; +import sosteam.throwapi.domain.user.service.UserSeaerchService; +import sosteam.throwapi.global.service.JwtTokenService; import java.time.LocalDateTime; import java.util.Set; @@ -46,50 +40,59 @@ public class StoreController { private final StoreCreateService storeCreateService; private final StoreModifyService storeModifyService; private final StoreDeleteService storeDeleteService; + private final BiznoService biznoService; + private final JwtTokenService jwtTokenService; + private final UserSeaerchService userSearchService; - private final BiznoAPI biznoAPI; - ObjectMapper mapper = new ObjectMapper(); - + /** + * 새로운 가게를 등록합니다. + * @param auth 사용자의 토큰 + * @param request 생성할 가게 정보 + * @return 가게의 외부 UUID + */ @PostMapping public ResponseEntity saveStore( @RequestHeader(name = "Authorization", required = true) String auth, - @RequestBody @Valid StoreSaveRequest request ) { - // Bizno RegistrationNumber Confirm API Error checking - String storeName = confirmCompanyRegistrationNumber(request.getCrn(),auth); - log.debug("POST : BIZNO API RESULT : StoreName ={}",storeName); + // 비즈노 API 호출 성공 시, 해당 사업자 번호의 가게 이름을 가져옵니다. String accessToken = auth.split(" ")[1]; - // if CompanyRegistrationNumber Form is XXX-XX-XXXXX, - // remove '-' - // Call save Service + String storeName = biznoService.confirmCompanyRegistrationNumber(request.getCrn(), accessToken); + + // Bearer qwee..가 acdessToken이므로 실제 토큰인 뒷 부분을 가져옵니다. + UUID userId = getUserByToken(accessToken); + + // 사업자 번호 입력 시 "-" 를 제거합니다 + String crn = request.getCrn().replaceAll("-", ""); StoreSaveDto dto = new StoreSaveDto( - accessToken, null, storeName, request.getStorePhone(), - request.getCrn().replaceAll("-",""), + crn, request.getLatitude(), request.getLongitude(), request.getZipCode(), request.getFullAddress(), request.getTrashType() ); - log.debug("StoreSaveRequest = {}", dto); - - Store store = storeCreateService.saveStore(dto); - + Store store = storeCreateService.saveStore(userId,dto); return ResponseEntity.ok(store.getExtStoreId()); } + /** + * 내 가게 불러오기 + * @param auth 사용자 토큰 + * @return 해당 사용자의 가게들을 반환 + */ @GetMapping("/user") public ResponseEntity> searchMyStores( @RequestHeader(name = "Authorization", required = true) String auth ) { String accessToken = auth.split(" ")[1]; - Set storeDtos = storeSearchService.searchMyStores(accessToken); + UUID userId = getUserByToken(accessToken); + Set storeDtos = storeSearchService.searchMyStores(userId); Set resp = storeDtos.stream().map(StoreDto::toResponse).collect(Collectors.toSet()); return ResponseEntity.ok(resp); } @@ -112,6 +115,7 @@ public ResponseEntity> searchStoreInRadius(@RequestBody @Vali request.getDistance(), request.getTrashType().replace("0","_") ); + // Convert Dto to Response Set storeDtos = storeSearchService.searchStoreInRadius(dto); Set resp = storeDtos.stream().map(StoreDto::toResponse).collect(Collectors.toSet()); @@ -129,7 +133,6 @@ public ResponseEntity> searchStoreInRadius(@RequestBody @Vali @PostMapping("/crn") public ResponseEntity searchByCompanyRegistrationNumber(@RequestBody @Valid StoreCrnRequest request) { StoreDto dto = storeSearchService.searchByCRN(request.getCrn().replaceAll("-","")); - if(dto == null) throw new NoSuchStoreException(); StoreResponse resp = dto.toResponse(); return ResponseEntity.ok(resp); } @@ -157,63 +160,69 @@ public ResponseEntity> searchByName(@RequestBody @Valid Store public ResponseEntity modifyStore( @RequestHeader(name = "Authorization", required = true) String auth, - @RequestBody @Valid StoreModifyRequest request ) { + // Bearer qwee..가 acdessToken이므로 실제 토큰인 뒷 부분을 가져옵니다. String accessToken = auth.split(" ")[1]; - // Bizno RegistrationNumber Confirm API Error checking - String storeName = confirmCompanyRegistrationNumber(request.getCrn(),auth); - log.debug("PUT: BIZNO API RESULT : StoreName ={}",storeName); + UUID userId = getUserByToken(accessToken); - // if CompanyRegistrationNumber Form is XXX-XX-XXXXX, - // remove '-' + // 비즈노 호출 성공 시 가게 이름을 받는다. + String storeName = biznoService.confirmCompanyRegistrationNumber(request.getCrn(), accessToken); + + // 사업자 번호 입력 시 "-" 를 제거합니다 + String crn = request.getCrn().replaceAll("-", ""); + + // 수정 데이터가 담긴 dto를 생성합니다. StoreDto dto = new StoreDto( request.getExtStoreId(), storeName, request.getStorePhone(), - request.getCrn().replaceAll("-",""), + crn, request.getLatitude(), request.getLongitude(), request.getZipCode(), request.getFullAddress(), request.getTrashType() ); - // Call modify Method - log.debug("StoreModifyRequest = {}", dto); - StoreDto storeDto = storeModifyService.modify(accessToken,dto); + + // 수정 서비스를 호출합니다. + StoreDto storeDto = storeModifyService.modify(userId,dto); + + // 수정이 완료되었다면, 수정 된 가게 데이터를 반환합니다. return ResponseEntity.ok(storeDto.toResponse()); } + /** + * 요청 가게를 삭제합니다. + * @param auth 요청한 사용자 토큰 + * @param request 삭제를 원하는 가게의 외부 UUID + * @return 삭제 완료 문구 + */ @DeleteMapping public ResponseEntity deleteStore( @RequestHeader(name = "Authorization", required = true) String auth, - @RequestBody @Valid StoreDeleteRequest request ) { + // Bearer qwee..가 acdessToken이므로 실제 토큰인 뒷 부분을 가져옵니다. String accessToken = auth.split(" ")[1]; - storeDeleteService.deleteStore(accessToken,request.getExtStoreId()); + UUID userId = getUserByToken(accessToken); + + // 가게 삭제 서비스 호출 + storeDeleteService.deleteStore(userId,request.getExtStoreId()); + + // 삭제 서비스가 완료되면 삭제 된 가게의 외부 UUID와 삭제 된 시간을 문자열로 반환합니다. String resp = "Delete Store: " + request.getExtStoreId() + "<" + String.valueOf(LocalDateTime.now()) + ">"; return ResponseEntity.ok(resp); } - /** - * BIZNO API를 이용하여 해당 사업자 번호가 국세청에 등록된 번호인지 확인 - * @param number 사업자 등록 번호 - * @return result 사업자 등록 번호로 등록된 가게 이름 -> storeName - * response.getResultCode() : - * -1 : 미등록 사용자 -> Wrong API-KEY - * -2 : 파라메터 오류` - * -3 : 1일 100건 조회수 초과 - * 9 : 기타 오류 - * -10 : 해당 번호 존재 X - */ - public String confirmCompanyRegistrationNumber(String number,String accessToken){ - BiznoApiResponse response = biznoAPI.confirmCompanyRegistrationNumber(number,accessToken); - if( response == null || response.getTotalCount() == 0) throw new NoSuchRegistrationNumberException(); - if(response.getResultCode() < 0) throw new BiznoAPIException(response.getResultCode()); - return response.getItems().get(0).getCompany(); + // 토큰을 통해 사용자를 가져 옵니다. + public UUID getUserByToken(String token) { + UserInfoDto userInfoDto = new UserInfoDto( + jwtTokenService.extractSubject(token) + ); + return userSearchService.searchByInputId(userInfoDto).getId(); } } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/request/StoreDeleteRequest.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/request/StoreDeleteRequest.java index d0c99aaa..503207e2 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/request/StoreDeleteRequest.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/controller/request/StoreDeleteRequest.java @@ -1,9 +1,7 @@ package sosteam.throwapi.domain.store.controller.request; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; import lombok.Data; -import org.hibernate.validator.constraints.Range; import java.util.UUID; diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Address.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Address.java index 2b94419d..1a9f428c 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Address.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Address.java @@ -1,9 +1,6 @@ package sosteam.throwapi.domain.store.entity; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.OneToOne; +import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import lombok.AccessLevel; import lombok.Getter; @@ -40,7 +37,8 @@ public Address(Point location, double latitude, double longitude, String fullAdd this.zipCode = zipCode; } - @OneToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id") private Store store; public Store modifyStore(Store store){ diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Store.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Store.java index 74d319c8..8e4bdb9f 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Store.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/Store.java @@ -10,6 +10,7 @@ import sosteam.throwapi.domain.user.entity.User; import sosteam.throwapi.global.entity.PrimaryKeyEntity; +import java.util.List; import java.util.UUID; @Getter @@ -34,19 +35,19 @@ public class Store extends PrimaryKeyEntity { // 일반쓰레기 | 병 | 플라스틱 | 종이 | 캔 @NotNull private String trashType; + @NotNull @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") private User user; - @NotNull - @OneToOne( + + @OneToMany( mappedBy = "store", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true ) - @JoinColumn(name = "address_id") - private Address address; + private List
address; public Store(UUID extStoreId, String storeName, String storePhone, String companyRegistrationNumber, String trashType) { this.extStoreId = extStoreId; @@ -68,7 +69,7 @@ public User modifyUser(User user) { return this.user; } - public Address modifyAddress(Address address) { + public List
modifyAddress(List
address) { this.address = address; return this.address; } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/dto/StoreSaveDto.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/dto/StoreSaveDto.java index 3f30cb51..5aa3d2b4 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/dto/StoreSaveDto.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/entity/dto/StoreSaveDto.java @@ -1,6 +1,5 @@ package sosteam.throwapi.domain.store.entity.dto; -import com.querydsl.core.annotations.QueryProjection; import lombok.AllArgsConstructor; import lombok.Data; @@ -9,7 +8,6 @@ @Data @AllArgsConstructor public class StoreSaveDto { - private String accessToken; private UUID extStoreId; private String storeName; private String storePhone; diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/InvalidRequestException.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/InvalidRequestException.java index 09f6bc8c..364ea63f 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/InvalidRequestException.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/InvalidRequestException.java @@ -5,6 +5,6 @@ public class InvalidRequestException extends CommonException { public InvalidRequestException(String code) { - super("INVALID_REQUEST_OF_"+code, "검증 실패! : 잘못된 접근입니다.", HttpStatus.BAD_REQUEST); + super("INVALID_REQUEST_OF_"+code, "검증 실패! : 잘못된 접근입니다.", HttpStatus.UNAUTHORIZED); } } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/NoSuchRegistrationNumberException.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/NoSuchRegistrationNumberException.java index d3db6460..f4bacaba 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/NoSuchRegistrationNumberException.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/NoSuchRegistrationNumberException.java @@ -5,6 +5,6 @@ public class NoSuchRegistrationNumberException extends CommonException { public NoSuchRegistrationNumberException() { - super("NO_SUCH_REGISTRATION_NUMBER", "국세청에 등록되지 않은 사업자등록번호입니다.", HttpStatus.BAD_REQUEST); + super("NO_SUCH_REGISTRATION_NUMBER", "국세청에 등록되지 않은 사업자등록번호입니다.", HttpStatus.UNAUTHORIZED); } } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/WrongStoreIdException.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/WrongStoreIdException.java index 473c6fcf..948c197a 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/WrongStoreIdException.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/exception/WrongStoreIdException.java @@ -5,6 +5,6 @@ public class WrongStoreIdException extends CommonException { public WrongStoreIdException() { - super("STORE_ID_DON'T_MATCH", "가게 아이디가 올바르지 않습니다.", HttpStatus.BAD_REQUEST); + super("STORE_ID_DON'T_MATCH", "가게 아이디가 올바르지 않습니다.", HttpStatus.UNAUTHORIZED); } } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLog.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLog.java index 699d2627..6c8edc24 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLog.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLog.java @@ -3,6 +3,8 @@ import jakarta.persistence.*; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; import sosteam.throwapi.global.service.TimeStamped; import java.util.UUID; @@ -17,7 +19,8 @@ public class CrnLog extends TimeStamped { @Column private String ip; - @Column + @Column(name = "user_id", updatable = false, nullable = false, columnDefinition = "VARCHAR(36)") + @JdbcTypeCode(SqlTypes.VARCHAR) private UUID userId; public CrnLog(String ip, UUID userId) { diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLogRepository.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLogRepository.java index a55a1a0a..219373d7 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLogRepository.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/log/CrnLogRepository.java @@ -1,7 +1,6 @@ package sosteam.throwapi.domain.store.log; import org.springframework.data.jpa.repository.JpaRepository; -import sosteam.throwapi.domain.store.log.CrnLog; public interface CrnLogRepository extends JpaRepository { } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustom/StoreCustomRepository.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustom/StoreCustomRepository.java index 27b6ae75..ed512f1a 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustom/StoreCustomRepository.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustom/StoreCustomRepository.java @@ -2,8 +2,8 @@ import sosteam.throwapi.domain.store.entity.Address; import sosteam.throwapi.domain.store.entity.Store; -import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; import sosteam.throwapi.domain.store.entity.dto.StoreDto; +import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; import java.util.Optional; import java.util.Set; diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustomImpl/StoreCustomRepositoryImpl.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustomImpl/StoreCustomRepositoryImpl.java index 2d10be57..92771462 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustomImpl/StoreCustomRepositoryImpl.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/repository/repoCustomImpl/StoreCustomRepositoryImpl.java @@ -1,8 +1,6 @@ package sosteam.throwapi.domain.store.repository.repoCustomImpl; -import com.querydsl.core.types.Ops; import com.querydsl.core.types.Projections; -import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.StringTemplate; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -13,8 +11,8 @@ import sosteam.throwapi.domain.store.entity.QAddress; import sosteam.throwapi.domain.store.entity.QStore; import sosteam.throwapi.domain.store.entity.Store; -import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; import sosteam.throwapi.domain.store.entity.dto.StoreDto; +import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; import sosteam.throwapi.domain.store.repository.repoCustom.StoreCustomRepository; import sosteam.throwapi.domain.user.entity.QUser; @@ -31,7 +29,6 @@ public class StoreCustomRepositoryImpl implements StoreCustomRepository { private final QAddress qAddress; private final QUser qUser; @Autowired - public StoreCustomRepositoryImpl(JPAQueryFactory jpaQueryFactory) { this.jpaQueryFactory = jpaQueryFactory; this.qStore = QStore.store; @@ -108,6 +105,7 @@ public Optional
searchAddressByStore(UUID uuid) { Address address = jpaQueryFactory .selectFrom(qAddress) .innerJoin(qAddress.store,qStore) + .fetchJoin() .where(qStore.id.eq(uuid)) .fetchOne(); return Optional.ofNullable(address); diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/BiznoService.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/BiznoService.java new file mode 100644 index 00000000..02b2b263 --- /dev/null +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/BiznoService.java @@ -0,0 +1,33 @@ +package sosteam.throwapi.domain.store.service; + + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import sosteam.throwapi.domain.store.exception.BiznoAPIException; +import sosteam.throwapi.domain.store.exception.NoSuchRegistrationNumberException; +import sosteam.throwapi.domain.store.externalAPI.bizno.BiznoAPI; +import sosteam.throwapi.domain.store.externalAPI.bizno.BiznoApiResponse; + +@Service +@RequiredArgsConstructor +public class BiznoService { + private final BiznoAPI biznoAPI; + + /** + * BIZNO API를 이용하여 해당 사업자 번호가 국세청에 등록된 번호인지 확인 + * @param number 사업자 등록 번호 + * @return result 사업자 등록 번호로 등록된 가게 이름 -> storeName + * response.getResultCode() : + * -1 : 미등록 사용자 -> Wrong API-KEY + * -2 : 파라메터 오류` + * -3 : 1일 100건 조회수 초과 + * 9 : 기타 오류 + * -10 : 해당 번호 존재 X + */ + public String confirmCompanyRegistrationNumber(String number,String accessToken){ + BiznoApiResponse response = biznoAPI.confirmCompanyRegistrationNumber(number,accessToken); + if( response == null || response.getTotalCount() == 0) throw new NoSuchRegistrationNumberException(); + if(response.getResultCode() < 0) throw new BiznoAPIException(response.getResultCode()); + return response.getItems().get(0).getCompany(); + } +} diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreCreateService.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreCreateService.java index 6ba9e6da..164757ee 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreCreateService.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreCreateService.java @@ -13,10 +13,10 @@ import sosteam.throwapi.domain.store.repository.repo.StoreRepository; import sosteam.throwapi.domain.store.util.GeometryUtil; import sosteam.throwapi.domain.user.entity.User; -import sosteam.throwapi.domain.user.entity.dto.user.UserInfoDto; -import sosteam.throwapi.domain.user.service.UserSeaerchService; -import sosteam.throwapi.global.service.JwtTokenService; +import sosteam.throwapi.domain.user.exception.NoSuchUserException; +import sosteam.throwapi.domain.user.repository.UserRepository; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -26,28 +26,18 @@ @RequiredArgsConstructor public class StoreCreateService { private final StoreRepository storeRepository; - private final StoreSearchService storeSearchService; + private final UserRepository userRepository; - private final UserSeaerchService userSearchService; - private final JwtTokenService jwtTokenService; @Transactional - public Store saveStore(StoreSaveDto storeDto) { - log.debug("Start Creating Store = {}", storeDto); - // if Store is already Exist - // return 409 : Conflict http status - Optional result = storeSearchService.isExistByCRN(storeDto.getCrn()); + public Store saveStore(UUID userId,StoreSaveDto storeDto) { + log.debug("가게 저장 서비스 시작 = {}", storeDto); + // 만약에 해당 사업자 번호로 등록된 가게가 존재할 경우, + Optional result = storeRepository.searchByCRN(storeDto.getCrn()); + // 409 충돌 에러를 반환 합니다. if (result.isPresent()) throw new StoreAlreadyExistException(); - - - // 요청 사용자 정보 가져오기 - UserInfoDto userInfoDto = new UserInfoDto( - jwtTokenService.extractSubject(storeDto.getAccessToken()) - ); - User user = userSearchService.searchByInputId(userInfoDto); - - // Make external Store id using UUID + // 가게 외부 노출용 UUID를 생성합니다. UUID extStoreId = UUID.randomUUID(); - // 1: Create Store Entity + // 1. 가게 객체 생성 Store store = new Store( extStoreId, storeDto.getStoreName(), @@ -56,13 +46,12 @@ public Store saveStore(StoreSaveDto storeDto) { storeDto.getTrashType() ); - // 2: Create Address Entity - // 2-1 : Create Point based on Lat,Lon + // 2: 주소 객체 생성 + // 2-1 : 위도 경도를 통해 POINT 타입 멤버를 만듭니다. Point location = GeometryUtil.parseLocation( storeDto.getLatitude(), storeDto.getLongitude() ); - log.debug("location={}", location); Address address = new Address( location, storeDto.getLatitude(), @@ -71,17 +60,25 @@ public Store saveStore(StoreSaveDto storeDto) { storeDto.getZipCode() ); - // 4: Mapping Store and Address - store.modifyAddress(address); + // 4: 가게와 주소 객체를 연결 합니다. address.modifyStore(store); + List
addresses = new ArrayList<>(); + addresses.add(address); + store.modifyAddress(addresses); + + // 사용자 불러오기 + User user = userRepository.findById(userId).orElseThrow(NoSuchUserException::new); - // 5: Mapping Store and User + // 5: 가게와 사용자 객체를 연결 합니다. store.modifyUser(user); List stores = user.getStores(); + if(stores == null) { + stores = new ArrayList<>(); + user.modifyStore(stores); + } stores.add(store); - user.modifyStore(stores); - // 6: save Store Entity + // 6: 가게 객체를 저장 합니다. return storeRepository.save(store); } } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreDeleteService.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreDeleteService.java index d2ddd49e..09e94b65 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreDeleteService.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreDeleteService.java @@ -3,15 +3,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import sosteam.throwapi.domain.store.entity.Address; import sosteam.throwapi.domain.store.entity.Store; import sosteam.throwapi.domain.store.exception.InvalidRequestException; import sosteam.throwapi.domain.store.exception.NoSuchStoreException; import sosteam.throwapi.domain.store.repository.repo.StoreRepository; import sosteam.throwapi.domain.user.entity.User; -import sosteam.throwapi.domain.user.entity.dto.user.UserInfoDto; -import sosteam.throwapi.domain.user.service.UserSeaerchService; -import sosteam.throwapi.global.service.JwtTokenService; +import sosteam.throwapi.domain.user.repository.UserRepository; import java.util.Optional; import java.util.UUID; @@ -21,37 +18,25 @@ @RequiredArgsConstructor public class StoreDeleteService { private final StoreRepository storeRepository; - private final UserSeaerchService userSearchService; - private final JwtTokenService jwtTokenService; - - - public void deleteStore(String accessToken, UUID extStoreId) { - // 요청 사용자 정보 가져오기 - UserInfoDto userInfoDto = new UserInfoDto( - jwtTokenService.extractSubject(accessToken) - ); - User user = userSearchService.searchByInputId(userInfoDto); - + private final UserRepository userRepository; + public UUID deleteStore(UUID userId, UUID extStoreId) { + // 가게 외부 UUID로 해당 가게를 불러옵니다. Optional optionalStore = storeRepository.searchByExtStoreId(extStoreId); if (optionalStore.isEmpty()) throw new NoSuchStoreException(); Store store = optionalStore.get(); - // check if the store's owner is same with request-user - UUID userId = storeRepository.searchUserByStore(store).orElseThrow(NoSuchStoreException::new); - //log.debug("userId1:{}, userId2:{}", user.getId(), userId); - if (userId.compareTo(user.getId()) != 0) throw new InvalidRequestException("DELETE"); - - - Optional
optionalAddress = storeRepository.searchAddressByStore(store.getId()); - if (optionalAddress.isEmpty()) throw new NoSuchStoreException(); - Address address = optionalAddress.get(); + // 삭제를 요청한 사용자와 해당 가게의 주인이 동일 인물인지 확인합니다. + User user = userRepository.findById(userId).orElseThrow(NoSuchStoreException::new); + UUID findUserId = storeRepository.searchUserByStore(store).orElseThrow(()-> new InvalidRequestException("DELETE")); + if (findUserId.compareTo(user.getId()) != 0) throw new InvalidRequestException("DELETE"); if ( store.getExtStoreId().equals(extStoreId) ) { - store.modifyAddress(null); - address.modifyStore(null); + // 가게와 주소의 연관관계를 끊어줍니다. storeRepository.delete(store); } else throw new InvalidRequestException("DELETE"); + + return extStoreId; } } diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreModifyService.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreModifyService.java index d2344fe8..990a52d5 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreModifyService.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreModifyService.java @@ -14,9 +14,8 @@ import sosteam.throwapi.domain.store.repository.repo.StoreRepository; import sosteam.throwapi.domain.store.util.GeometryUtil; import sosteam.throwapi.domain.user.entity.User; -import sosteam.throwapi.domain.user.entity.dto.user.UserInfoDto; -import sosteam.throwapi.domain.user.service.UserSeaerchService; -import sosteam.throwapi.global.service.JwtTokenService; +import sosteam.throwapi.domain.user.exception.NoSuchUserException; +import sosteam.throwapi.domain.user.repository.UserRepository; import java.util.Optional; import java.util.UUID; @@ -26,9 +25,7 @@ @RequiredArgsConstructor public class StoreModifyService { private final StoreRepository storeRepository; - private final UserSeaerchService userSearchService; - private final JwtTokenService jwtTokenService; - + private final UserRepository userRepository; /** * 가게 정보를 수정하는 메소드 * @@ -41,31 +38,31 @@ public class StoreModifyService { * 만약 가게 코드가 올바르지 않으면 데이터의 무결성이 안지켜진것이므로 수정 시도를 막는다. */ @Transactional - public StoreDto modify(String accessToken, StoreDto dto) { - // 요청 사용자 정보 가져오기 - UserInfoDto userInfoDto = new UserInfoDto( - jwtTokenService.extractSubject(accessToken) - ); - User user = userSearchService.searchByInputId(userInfoDto); - - // Find Store By given storeId + public StoreDto modify(UUID userId, StoreDto dto) { + // 가게 외부 UUID를 통해 해당 가게를 가져옵니다. Optional optionalStore = storeRepository.searchByExtStoreId(dto.getExtStoreId()); if (optionalStore.isEmpty()) throw new WrongStoreIdException(); Store store = optionalStore.get(); - // check if the store's owner is same with request-user - UUID userId = storeRepository.searchUserByStore(store).orElseThrow(NoSuchStoreException::new); - if (userId.compareTo(user.getId()) != 0) throw new InvalidRequestException("MODIFY"); + // 불러온 가게의 주인이 수정 요청을 한 사용자와 동일 인물인지 확인합니다. + User user = userRepository.findById(userId).orElseThrow(NoSuchUserException::new); + UUID findUserId = storeRepository.searchUserByStore(store).orElseThrow(()-> new InvalidRequestException("MODIFY")); + if (findUserId.compareTo(user.getId()) != 0) throw new InvalidRequestException("MODIFY"); + // 가게 정보를 수정합니다. store.modify( dto.getStoreName(), dto.getStorePhone(), dto.getCrn(), dto.getTrashType() ); + + // 가게의 주소 정보를 가져옵니다. Optional
optionalAddress = storeRepository.searchAddressByStore(store.getId()); if (optionalAddress.isEmpty()) throw new NoSuchStoreException(); Address address = optionalAddress.get(); + + // 주소 정보를 수정합니다. Point location = GeometryUtil.parseLocation( dto.getLatitude(), dto.getLongitude() @@ -77,6 +74,7 @@ public StoreDto modify(String accessToken, StoreDto dto) { dto.getFullAddress(), dto.getZipCode() ); + storeRepository.save(store); return new StoreDto( dto.getExtStoreId(), dto.getStoreName(), diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreSearchService.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreSearchService.java index ce9eca38..582d8304 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreSearchService.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/store/service/StoreSearchService.java @@ -7,31 +7,25 @@ import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.Point; import org.springframework.stereotype.Service; -import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; import sosteam.throwapi.domain.store.entity.dto.StoreDto; +import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; import sosteam.throwapi.domain.store.exception.NoStoreOfUserException; import sosteam.throwapi.domain.store.exception.NoSuchStoreException; import sosteam.throwapi.domain.store.repository.repo.StoreRepository; import sosteam.throwapi.domain.store.util.Direction; import sosteam.throwapi.domain.store.util.GeometryUtil; -import sosteam.throwapi.domain.user.entity.User; -import sosteam.throwapi.domain.user.entity.dto.user.UserInfoDto; -import sosteam.throwapi.domain.user.service.UserSeaerchService; import sosteam.throwapi.global.exception.exception.NoContentException; import sosteam.throwapi.global.exception.exception.NotFoundException; -import sosteam.throwapi.global.service.JwtTokenService; import java.util.Optional; import java.util.Set; +import java.util.UUID; @Slf4j @Service @RequiredArgsConstructor public class StoreSearchService { private final StoreRepository storeRepository; - private final UserSeaerchService userSearchService; - - private final JwtTokenService jwtTokenService; /** * 1: Make two points that are (distance) km apart from the current location @@ -111,13 +105,9 @@ public Optional isExistByCRN(String crn) { return storeRepository.searchByCRN(crn); } - public Set searchMyStores(String accessToken) { + public Set searchMyStores(UUID uuid) { // 요청 사용자 정보 가져오기 - UserInfoDto userInfoDto = new UserInfoDto( - jwtTokenService.extractSubject(accessToken) - ); - User user = userSearchService.searchByInputId(userInfoDto); - Optional> storeDtos = storeRepository.searchMyStores(user.getId()); + Optional> storeDtos = storeRepository.searchMyStores(uuid); if(storeDtos.isEmpty()) throw new NoStoreOfUserException(); if(storeDtos.get().isEmpty()) throw new NoContentException(); return storeDtos.get(); diff --git a/api/throwapi/src/main/java/sosteam/throwapi/domain/user/entity/User.java b/api/throwapi/src/main/java/sosteam/throwapi/domain/user/entity/User.java index f7b0ef62..b62e6082 100644 --- a/api/throwapi/src/main/java/sosteam/throwapi/domain/user/entity/User.java +++ b/api/throwapi/src/main/java/sosteam/throwapi/domain/user/entity/User.java @@ -66,7 +66,7 @@ public class User extends PrimaryKeyEntity implements UserDetails { @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL) private Mileage mileage; - @OneToMany(mappedBy = "user", fetch = FetchType.LAZY) + @OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) private List stores; @OneToMany(mappedBy = "user", fetch = FetchType.LAZY) diff --git a/api/throwapi/src/test/java/sosteam/throwapi/service/BiznoServiceTest.java b/api/throwapi/src/test/java/sosteam/throwapi/service/BiznoServiceTest.java new file mode 100644 index 00000000..0ce54649 --- /dev/null +++ b/api/throwapi/src/test/java/sosteam/throwapi/service/BiznoServiceTest.java @@ -0,0 +1,98 @@ +package sosteam.throwapi.service; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +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 sosteam.throwapi.domain.store.exception.BiznoAPIException; +import sosteam.throwapi.domain.store.exception.NoSuchRegistrationNumberException; +import sosteam.throwapi.domain.store.externalAPI.bizno.BiznoAPI; +import sosteam.throwapi.domain.store.externalAPI.bizno.BiznoApiResponse; +import sosteam.throwapi.domain.store.service.BiznoService; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.BDDMockito.given; +@ExtendWith(MockitoExtension.class) +public class BiznoServiceTest { + + @InjectMocks + BiznoService biznoService; + + @Mock + BiznoAPI biznoAPI; + + @Nested + @DisplayName("비즈노 API 호출") + class Bizno { + @Test + @DisplayName("비즈노 호출 성공 시 가게 이름을 가져온다") + void successfulBiznoCall() { + // given + List items = new ArrayList<>(); + items.add(new BiznoApiResponse.Items("테스트 김밥")); + BiznoApiResponse response = new BiznoApiResponse( + 0, + "test", + 1, + items + ); + given(biznoAPI.confirmCompanyRegistrationNumber("1233212343", "test")).willReturn(response); + + //when + String result = biznoService.confirmCompanyRegistrationNumber("1233212343", "test"); + + //then + Assertions.assertThat(result).isEqualTo("테스트 김밥"); + } + + @Test + @DisplayName("비즈노 호출 실패 테스트: 사업자 번호 존재 X") + void unsuccessfulBiznoCall() { + // 비즈노 호출 시 응답 값이 null 이거나 totalCount가 0이면 예외를 발생한다 + // case 1, case 2 하나 씩 실행해야함 다른거 하나는 주석처리하고 실행하면 된다. + + // given 1 + //given(biznoAPI.confirmCompanyRegistrationNumber("1231212345", "test")).willReturn(null); + // given 2 + BiznoApiResponse response = new BiznoApiResponse( + -9, + "test", + 0, + null + ); + given(biznoAPI.confirmCompanyRegistrationNumber("1231212345", "test")).willReturn(response); + //when-then + assertThrows(NoSuchRegistrationNumberException.class, () -> biznoService.confirmCompanyRegistrationNumber("1231212345", "test")); + + //then + // 예외가 발생해야합니다 + //fail("가게 관련 예외가 발생해야 합니다"); + } + @Test + @DisplayName("비즈노 호출 실패 테스트: 비즈노 관련 에러 X") + void unsuccessfulBiznoCallByBizno() { + // result code가 -9이므로 비즈노 측 에러 발생 + // given + BiznoApiResponse response = new BiznoApiResponse( + -9, + "test", + 1, + null + ); + given(biznoAPI.confirmCompanyRegistrationNumber("1231212345", "test")).willReturn(response); + //when-then + assertThrows(BiznoAPIException.class, () -> biznoService.confirmCompanyRegistrationNumber("1231212345", "test")); + + //then + // 예외가 발생해야합니다 + //fail("가게 관련 예외가 발생해야 합니다"); + } + } +} diff --git a/api/throwapi/src/test/java/sosteam/throwapi/service/StoreCreateServiceTest.java b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreCreateServiceTest.java new file mode 100644 index 00000000..d06e9484 --- /dev/null +++ b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreCreateServiceTest.java @@ -0,0 +1,69 @@ +package sosteam.throwapi.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +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 sosteam.throwapi.domain.store.entity.Store; +import sosteam.throwapi.domain.store.entity.dto.StoreSaveDto; +import sosteam.throwapi.domain.store.repository.repo.StoreRepository; +import sosteam.throwapi.domain.store.service.StoreCreateService; +import sosteam.throwapi.domain.user.entity.User; +import sosteam.throwapi.domain.user.repository.UserRepository; + +import java.util.Optional; +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class StoreCreateServiceTest { + @InjectMocks + StoreCreateService storeCreateService; + + @Mock + UserRepository userRepository; + @Mock + StoreRepository storeRepository; + @Nested + @DisplayName("가게 저장하기") + class storeCreate{ + @Test + @DisplayName("새로운 가게를 저장합니다") + void saveStore() { + // given + User user = new User(); + StoreSaveDto storeDto = new StoreSaveDto( + UUID.randomUUID(), + "테스트가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + Store store = new Store( + UUID.randomUUID(), + "테스트가게", + "01052783309", + "0101010101", + "00000" + ); + when(userRepository.findById(user.getId())).thenReturn(Optional.of(user)); + doReturn(store).when(storeRepository).save(any(Store.class)); + //given(storeRepository.save(store)).willReturn(store); + + //when + storeCreateService.saveStore(user.getId(),storeDto); + + // then + verify(storeRepository).save(any()); + } + } +} diff --git a/api/throwapi/src/test/java/sosteam/throwapi/service/StoreDeleteServiceTest.java b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreDeleteServiceTest.java new file mode 100644 index 00000000..b1be3b2c --- /dev/null +++ b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreDeleteServiceTest.java @@ -0,0 +1,99 @@ +package sosteam.throwapi.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +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 sosteam.throwapi.domain.store.entity.Address; +import sosteam.throwapi.domain.store.entity.Store; +import sosteam.throwapi.domain.store.exception.InvalidRequestException; +import sosteam.throwapi.domain.store.exception.NoSuchStoreException; +import sosteam.throwapi.domain.store.repository.repo.StoreRepository; +import sosteam.throwapi.domain.store.service.StoreDeleteService; +import sosteam.throwapi.domain.user.entity.User; +import sosteam.throwapi.domain.user.repository.UserRepository; + +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class StoreDeleteServiceTest { + @InjectMocks + StoreDeleteService storeDeleteService; + @Mock + UserRepository userRepository; + @Mock + StoreRepository storeRepository; + + @Nested + @DisplayName("가게 삭제하기") + class storeDelete { + //given + User user = new User(); + UUID ext = UUID.randomUUID(); + Address address = new Address( + null, + 12, + 127, + "qwe", + "10298" + ); + Store store = new Store( + ext, + "테스트가게", + "01052783309", + "0101010101", + "00000" + ); + @Test + @DisplayName("가게를 삭제합니당") + void storeDeleteTest() { + // given + when(userRepository.findById(user.getId())).thenReturn(Optional.of(user)); + given(storeRepository.searchByExtStoreId(ext)).willReturn(Optional.of(store)); + given(storeRepository.searchUserByStore(store)).willReturn(Optional.of(user.getId())); + + // when + storeDeleteService.deleteStore(user.getId(), ext); + + // then + verify(storeRepository).delete(any()); + } + + @Test + @DisplayName("예외 : NO_SUCH_STORE_EXCEPTION") + void storeDoNotExistException() { + // given + //when(userRepository.findById(user.getId())).thenReturn(Optional.of(user)); + //given(storeRepository.searchByExtStoreId(ext)).willReturn(Optional.of(store)); + //given(storeRepository.searchUserByStore(store)).willReturn(Optional.of(user.getId())); + // when + assertThrows(NoSuchStoreException.class, () -> storeDeleteService.deleteStore(user.getId(), ext)); + // then + //fail("가게 관련 예외가 발생해야 합니다"); + } + + @Test + @DisplayName("예외 : INVALID_REQUEST") + void inValidRequestStoreDelete() { + // given + when(userRepository.findById(user.getId())).thenReturn(Optional.of(user)); + given(storeRepository.searchByExtStoreId(ext)).willReturn(Optional.of(store)); + //given(storeRepository.searchUserByStore(store)).willReturn(Optional.of(user.getId())); + //given(storeRepository.searchAddressByStore(store.getId())).willReturn(Optional.of(address)); + // when + assertThrows(InvalidRequestException.class, () -> storeDeleteService.deleteStore(user.getId(), ext)); + // then + //fail("가게 관련 예외가 발생해야 합니다"); + } + } +} diff --git a/api/throwapi/src/test/java/sosteam/throwapi/service/StoreModifyServiceTest.java b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreModifyServiceTest.java new file mode 100644 index 00000000..398abe49 --- /dev/null +++ b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreModifyServiceTest.java @@ -0,0 +1,114 @@ +package sosteam.throwapi.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +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 sosteam.throwapi.domain.store.entity.Address; +import sosteam.throwapi.domain.store.entity.Store; +import sosteam.throwapi.domain.store.entity.dto.StoreDto; +import sosteam.throwapi.domain.store.exception.InvalidRequestException; +import sosteam.throwapi.domain.store.exception.NoSuchStoreException; +import sosteam.throwapi.domain.store.repository.repo.StoreRepository; +import sosteam.throwapi.domain.store.service.StoreModifyService; +import sosteam.throwapi.domain.user.entity.User; +import sosteam.throwapi.domain.user.repository.UserRepository; + +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) +public class StoreModifyServiceTest { + + @InjectMocks + StoreModifyService storeModifyService; + @Mock + UserRepository userRepository; + @Mock + StoreRepository storeRepository; + + @Nested + @DisplayName("가게 수정하기") + class storeModify { + //given + User user = new User(); + UUID ext = UUID.randomUUID(); + Address address = new Address( + null, + 12, + 127, + "qwe", + "10298" + ); + Store store = new Store( + ext, + "테스트가게", + "01052783309", + "0101010101", + "00000" + ); + StoreDto dto = new StoreDto( + ext, + "테스트가게변경하자", + "01012341234", + "1111111111", + 13.1, + 129.1, + "01232", + "10298", + "10111" + ); + + @Test + @DisplayName("가게를 수정합니당") + void storeModifyTest() { + // given + when(userRepository.findById(user.getId())).thenReturn(Optional.of(user)); + given(storeRepository.searchByExtStoreId(ext)).willReturn(Optional.of(store)); + given(storeRepository.searchAddressByStore(store.getId())).willReturn(Optional.of(address)); + given(storeRepository.searchUserByStore(store)).willReturn(Optional.of(user.getId())); + // when + storeModifyService.modify(user.getId(), dto); + + // then + verify(storeRepository).save(any()); + } + + @Test + @DisplayName("예외 : NO_SUCH_STORE_EXCEPTION") + void storeDoNotExistException() { + // given + when(userRepository.findById(user.getId())).thenReturn(Optional.of(user)); + given(storeRepository.searchByExtStoreId(ext)).willReturn(Optional.of(store)); + given(storeRepository.searchUserByStore(store)).willReturn(Optional.of(user.getId())); + // 아래 코드가 없으면 NoSuchStore가 터진다. + //given(storeRepository.searchAddressByStore(store.getId())).willReturn(Optional.of(address)); + // when - then + assertThrows(NoSuchStoreException.class, () -> storeModifyService.modify(user.getId(), dto)); + // then + //fail("가게 관련 예외가 발생해야 합니다"); + } + + @Test + @DisplayName("예외 : INVALID_REQUEST") + void inValidRequestStoreDelete() { + // given + when(userRepository.findById(user.getId())).thenReturn(Optional.of(user)); + given(storeRepository.searchByExtStoreId(ext)).willReturn(Optional.of(store)); + // 아래 코드가 없으면 InvalidRequest가 터진다. + //given(storeRepository.searchUserByStore(store)).willReturn(Optional.of(user.getId())); + // when + assertThrows(InvalidRequestException.class, () -> storeModifyService.modify(user.getId(), dto)); + // then + //fail("가게 관련 예외가 발생해야 합니다"); + } + } +} diff --git a/api/throwapi/src/test/java/sosteam/throwapi/service/StoreSearchServiceTest.java b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreSearchServiceTest.java new file mode 100644 index 00000000..baa1a641 --- /dev/null +++ b/api/throwapi/src/test/java/sosteam/throwapi/service/StoreSearchServiceTest.java @@ -0,0 +1,195 @@ +package sosteam.throwapi.service; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +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 sosteam.throwapi.domain.store.entity.dto.StoreDto; +import sosteam.throwapi.domain.store.entity.dto.StoreInRadiusDto; +import sosteam.throwapi.domain.store.repository.repo.StoreRepository; +import sosteam.throwapi.domain.store.service.StoreCreateService; +import sosteam.throwapi.domain.store.service.StoreSearchService; +import sosteam.throwapi.domain.user.repository.UserRepository; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import static org.mockito.BDDMockito.given; + +@ExtendWith(MockitoExtension.class) +public class StoreSearchServiceTest { + @InjectMocks + StoreSearchService storeSearchService; + + @Mock + StoreRepository storeRepository; + + @Nested + @DisplayName("가게 검색하기") + class storeGet { + @Test + @DisplayName("내 가게 조회 서비스") + void myStores() { + // given + StoreDto storeDto = new StoreDto( + UUID.randomUUID(), + "테스트가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + StoreDto storeDto2 = new StoreDto( + UUID.randomUUID(), + "테스트가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + UUID myId = UUID.randomUUID(); + Set stores = new HashSet<>(); + stores.add(storeDto2); + stores.add(storeDto); + given(storeRepository.searchMyStores(myId)).willReturn(Optional.of(stores)); + + // when + Set result = storeSearchService.searchMyStores(myId); + + // then + Assertions.assertThat(result.size()).isEqualTo(2); + } + + @Test + @DisplayName("이름으로 가게 찾아보기") + void searchStoreByName() { + // given + StoreDto storeDto = new StoreDto( + UUID.randomUUID(), + "테스트1가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + StoreDto storeDto2 = new StoreDto( + UUID.randomUUID(), + "테스트2가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + Set stores = new HashSet<>(); + stores.add(storeDto); + stores.add(storeDto2); + given(storeRepository.searchByName("스트")).willReturn(Optional.of(stores)); + + // when + Set result = storeSearchService.searchStoreByName("스트"); + + // then + Assertions.assertThat(result.size()).isEqualTo(2); + } + + @Test + @DisplayName("사업자 등록번호로 가게 조회") + void searchStoreByCrn() { + // given + String crn = "0101010101"; + StoreDto storeDto = new StoreDto( + UUID.randomUUID(), + "테스트1가게", + "01052783309", + crn, + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + given(storeRepository.searchByCRN(crn)).willReturn(Optional.of(storeDto)); + + // when + StoreDto result = storeSearchService.searchByCRN(crn); + + // then + Assertions.assertThat(result.getCrn()).isEqualTo(storeDto.getCrn()); + } + + @Test + @DisplayName("반경 내 가게들을 검색합니다") + void searchStoreInRadius() { + // given + StoreDto storeDto = new StoreDto( + UUID.randomUUID(), + "테스트1가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + StoreDto storeDto2 = new StoreDto( + UUID.randomUUID(), + "테스트1가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + StoreDto storeDto3 = new StoreDto( + UUID.randomUUID(), + "테스트1가게", + "01052783309", + "0101010101", + 12.123, + 127.123, + "12341", + "테스트 주소", + "00000" + ); + StoreInRadiusDto dto = new StoreInRadiusDto( + 12.123, + 127.242, + 4, + null + ); + Set stores = new HashSet<>(); + stores.add(storeDto); + stores.add(storeDto2); + stores.add(storeDto3); + given(storeRepository.searchStoreInRadius(dto)).willReturn(Optional.of(stores)); + + // when + Set result = storeSearchService.searchStoreInRadius(dto); + + // then + Assertions.assertThat(result.size()).isEqualTo(stores.size()); + + } + } +}