diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/NoteRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/NoteRepository.java index f8c4830..9d9aca4 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/NoteRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/NoteRepository.java @@ -4,6 +4,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface NoteRepository extends JpaRepository { + + Optional findByName(String name); } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/RequestNoteRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/RequestNoteRepository.java index 70c89ab..3195971 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/RequestNoteRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/Note/repository/RequestNoteRepository.java @@ -3,5 +3,9 @@ import com.perfumepedia.perfumepedia.domain.note.entity.RequestNote; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface RequestNoteRepository extends JpaRepository { + + Optional findByName(String name); } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/brand/controller/BrandController.java b/src/main/java/com/perfumepedia/perfumepedia/domain/brand/controller/BrandController.java new file mode 100644 index 0000000..6f12204 --- /dev/null +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/brand/controller/BrandController.java @@ -0,0 +1,36 @@ +package com.perfumepedia.perfumepedia.domain.brand.controller; + +import com.perfumepedia.perfumepedia.domain.brand.service.BrandService; +import com.perfumepedia.perfumepedia.global.response.Response; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +@Tag(name = "관리자 대시보드", description = "관리자 대시보드 관련 API") + +public class BrandController { + + private final BrandService brandService; + + @Autowired + public BrandController(BrandService brandService) { + this.brandService = brandService; + } + + /** + * 모든 브랜드와 향수 개수 조회 api + */ + @GetMapping("/perfumes/admins/counts") + public ResponseEntity>> getBrandAndPerfumeCount() { + SuccessResponse> response = brandService.BrandAndPerfumeCount(); + return Response.success(response); + } + + +} diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/brand/repository/BrandRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/brand/repository/BrandRepository.java index 96e4eb5..8dcf162 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/brand/repository/BrandRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/brand/repository/BrandRepository.java @@ -5,8 +5,15 @@ import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface BrandRepository extends JpaRepository { - List findByNameContaining(String keyword); + + + // 해당 테이블의 모든 데이터 개수를 반환 + long count(); + + Optional findByName(String name); + } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/brand/service/BrandService.java b/src/main/java/com/perfumepedia/perfumepedia/domain/brand/service/BrandService.java index bbd8838..c14b6fb 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/brand/service/BrandService.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/brand/service/BrandService.java @@ -1,9 +1,41 @@ package com.perfumepedia.perfumepedia.domain.brand.service; +import com.perfumepedia.perfumepedia.domain.brand.repository.BrandRepository; +import com.perfumepedia.perfumepedia.domain.perfume.repository.PerfumeRepository; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.HashMap; +import java.util.Map; + +import static com.perfumepedia.perfumepedia.global.enums.SuccessCode.REQUEST_COMPLETED; + @Service public class BrandService { + private final BrandRepository brandRepository; + private final PerfumeRepository perfumeRepository; + + + @Autowired + public BrandService(BrandRepository brandRepository, PerfumeRepository perfumeRepository) { + this.brandRepository = brandRepository; + this.perfumeRepository = perfumeRepository; + } + + + /** + * 저장되어있는 브랜드와 향수의 개수를 반환하는 메서드 + */ + public SuccessResponse> BrandAndPerfumeCount() { + Map brandAndPerfumeCount = new HashMap<>(); + + brandAndPerfumeCount.put("brandCount", brandRepository.count()); + brandAndPerfumeCount.put("perfumeCount", perfumeRepository.count()); + + return new SuccessResponse<>(REQUEST_COMPLETED, brandAndPerfumeCount); + } + } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/controller/PerfumeController.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/controller/PerfumeController.java index 03d1d9f..bf4c6b3 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/controller/PerfumeController.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/controller/PerfumeController.java @@ -3,13 +3,12 @@ import com.perfumepedia.perfumepedia.domain.perfume.dto.PerfumeUpdateReq; import com.perfumepedia.perfumepedia.domain.perfume.service.PerfumeService; import com.perfumepedia.perfumepedia.domain.perfumeNote.dto.PerfumeDetailResponse; +import com.perfumepedia.perfumepedia.global.response.Response; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.List; @@ -26,22 +25,27 @@ public PerfumeController(PerfumeService perfumeService) { /** * 향수 검색 API (브랜드, 향수 이름, 노트 이름으로 검색) + * * @param keyword 검색어 * @return 검색된 향수 리스트 */ - @GetMapping("/api/searchs") - public ResponseEntity> searchPerfumes(@RequestParam String keyword) { - return ResponseEntity.ok(perfumeService.searchPerfumes(keyword)); + @GetMapping("/search") + public ResponseEntity>> searchPerfumes(@RequestParam String keyword) { + SuccessResponse> successResponse = perfumeService.searchPerfumes(keyword); + return Response.success(successResponse); } + /** * 향수 세부정보 조회 API ( + * * @param perfumeId 향수 아이디 * @return 검색된 향수 세부정보 */ - @GetMapping("/api/search/{id}") - public ResponseEntity getPerfumeDetail(@PathVariable Long perfumeId) { - return ResponseEntity.ok(perfumeService.getPerfumeDetail(perfumeId)); + @GetMapping("/search/{perfumeId}") + public ResponseEntity> getPerfumeDetail(@PathVariable Long perfumeId) { + SuccessResponse response = perfumeService.getPerfumeDetail(perfumeId); + return Response.success(response); } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/entity/RequestPerfume.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/entity/RequestPerfume.java index 43e6744..a6a0149 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/entity/RequestPerfume.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/entity/RequestPerfume.java @@ -24,7 +24,7 @@ public class RequestPerfume extends BaseEntity { @Column(name = "PRICE") private int price; - @ManyToOne + @ManyToOne(cascade = CascadeType.PERSIST) @JoinColumn(name = "REQUEST_BRAND_ID") private RequestBrand requestBrand; diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/PerfumeRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/PerfumeRepository.java index a490a21..45f3ed0 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/PerfumeRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/PerfumeRepository.java @@ -5,9 +5,15 @@ import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface PerfumeRepository extends JpaRepository { List findByNameContaining(String keyword); - List findByBrandNameContaining(String keyword); + + List findByBrand_NameContaining(String keyword); + + long count(); + + Optional findByName(String name); } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/RequestPerfumeRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/RequestPerfumeRepository.java index 6cba68e..72e9945 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/RequestPerfumeRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/repository/RequestPerfumeRepository.java @@ -3,5 +3,9 @@ import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface RequestPerfumeRepository extends JpaRepository { + + Optional findById(Long requestPerfumeId); } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/PerfumeService.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/PerfumeService.java index d37a5bd..9a01fab 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/PerfumeService.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/PerfumeService.java @@ -1,45 +1,72 @@ package com.perfumepedia.perfumepedia.domain.perfume.service; +import com.perfumepedia.perfumepedia.domain.brand.entity.Brand; +import com.perfumepedia.perfumepedia.domain.brand.repository.BrandRepository; +import com.perfumepedia.perfumepedia.domain.note.entity.Note; import com.perfumepedia.perfumepedia.domain.note.repository.NoteRepository; import com.perfumepedia.perfumepedia.domain.perfume.dto.PerfumeUpdateReq; import com.perfumepedia.perfumepedia.domain.perfume.entity.Perfume; +import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; import com.perfumepedia.perfumepedia.domain.perfume.repository.PerfumeRepository; +import com.perfumepedia.perfumepedia.domain.perfume.repository.RequestPerfumeRepository; import com.perfumepedia.perfumepedia.domain.perfumeNote.dto.PerfumeDetailResponse; import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.PerfumeNote; +import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.RequestPerfumeNote; import com.perfumepedia.perfumepedia.domain.perfumeNote.repository.PerfumeNoteRepository; -import com.perfumepedia.perfumepedia.global.enums.ErrorCode; +import com.perfumepedia.perfumepedia.domain.perfumeNote.repository.RequestPerfumeNoteRepository; +import com.perfumepedia.perfumepedia.domain.request.entity.Request; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestStatus; +import com.perfumepedia.perfumepedia.domain.request.repository.RequestRepository; +import com.perfumepedia.perfumepedia.global.enums.NoneResponse; import com.perfumepedia.perfumepedia.global.handler.AppException; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.*; +import static com.perfumepedia.perfumepedia.global.enums.ErrorCode.*; +import static com.perfumepedia.perfumepedia.global.enums.SuccessCode.*; + @Service public class PerfumeService { private PerfumeRepository perfumeRepository; private PerfumeNoteRepository perfumeNoteRepository; private NoteRepository noteRepository; + private BrandRepository brandRepository; + private RequestPerfumeNoteRepository requestPerfumeNoteRepository; + private RequestPerfumeRepository requestPerfumeRepository; + private RequestRepository requestRepository; + @Autowired - public PerfumeService(PerfumeRepository perfumeRepository, PerfumeNoteRepository perfumeNoteRepository, NoteRepository noteRepository) { - this.perfumeRepository = perfumeRepository; + public PerfumeService(PerfumeRepository perfumeRepository, PerfumeNoteRepository perfumeNoteRepository, + NoteRepository noteRepository, BrandRepository brandRepository, RequestPerfumeNoteRepository requestPerfumeNoteRepository, + RequestPerfumeRepository requestPerfumeRepository, RequestRepository requestRepository) { this.perfumeNoteRepository = perfumeNoteRepository; + this.perfumeRepository = perfumeRepository; this.noteRepository = noteRepository; + this.brandRepository = brandRepository; + this.requestPerfumeNoteRepository = requestPerfumeNoteRepository; + this.requestPerfumeRepository = requestPerfumeRepository; + this.requestRepository = requestRepository; } /** * 키워드별 향수 검색 + * * @param keyword 검색어 * @return 검색된 향수 리스트 */ - public List searchPerfumes(String keyword) { + public SuccessResponse> searchPerfumes(String keyword) { // 브렌드 이름으로 향수 검색 - List perfumesByBrand = perfumeRepository.findByBrandNameContaining(keyword); + List perfumesByBrand = perfumeRepository.findByBrand_NameContaining(keyword); // 향수 이름으로 향수 검색 List perfumesByName = perfumeRepository.findByNameContaining(keyword); // 노트 이름으로 향수 검색 - List perfumeNotes = perfumeNoteRepository.findByNoteContaining(keyword); + List perfumeNotes = perfumeNoteRepository.findByNote_NameContaining(keyword); // 중복 제거를 위함 Set resultPerfume = new HashSet<>(); @@ -51,40 +78,40 @@ public List searchPerfumes(String keyword) { resultPerfume.add(perfumeNote.getPerfume()); } // 검색 결과가 없을 경우 예외 처리 - if(resultPerfume.isEmpty()) { - throw new AppException(ErrorCode.PERFUME_NOT_FOUND); + if (resultPerfume.isEmpty()) { + throw new AppException(PERFUME_NOT_FOUND); } - // Perfume -> DTO로 변환 + // Perfume -> DTO List searchResult = new ArrayList<>(); for (Perfume perfume : resultPerfume) { searchResult.add(PerfumeUpdateReq.toDto(perfume)); } - return searchResult; + return new SuccessResponse<>(SEARCH_COMPLETED, searchResult); } /** - * 향수 세부 정보 조회 + * 향수 세부 정보 조회 + * * @param perfumaId 향수 아이디 * @return 검색된 향수 세부정보 */ - public PerfumeDetailResponse getPerfumeDetail(Long perfumaId) { + public SuccessResponse getPerfumeDetail(Long perfumaId) { // 해당하는 향수가 존재하는지 확인 Perfume perfume = perfumeRepository.findById(perfumaId) - .orElseThrow(() -> new AppException(ErrorCode.PERFUME_NOT_FOUND)); + .orElseThrow(() -> new AppException(PERFUME_NOT_FOUND)); // 해당하는 향수의 아이디를 가진 노트들을 조회 List perfumeNotes = perfumeNoteRepository.findByPerfumeId(perfumaId); if (perfumeNotes.isEmpty()) { - throw new AppException((ErrorCode.NOTE_NOT_FOUND)); + throw new AppException(NOTE_NOT_FOUND); } Map> notes = new HashMap<>(); - for (PerfumeNote perfumeNote : perfumeNotes) { String noteType = perfumeNote.getNoteType().name(); @@ -93,11 +120,187 @@ public PerfumeDetailResponse getPerfumeDetail(Long perfumaId) { } notes.get(noteType).add(perfumeNote.getNote().getName()); } + PerfumeDetailResponse detailPerfume = PerfumeDetailResponse.toDto(perfume, notes); + + + return new SuccessResponse<>(SEARCH_COMPLETED, detailPerfume); + } + + /** + * 요청 타입별 요청 수락 + */ + @Transactional + public SuccessResponse acceptPerfumeRequest(Long requestId) { + // 요청 정보 조회 + Request request = requestRepository.findById(requestId) + .orElseThrow(() -> new AppException(REQUEST_NOT_FOUND)); + + // 요청 타입에 따라 처리 + switch (request.getRequestType()) { + case CREATE: + return acceptRegisterRequest(request); // 등록 요청 처리 + case UPDATE: + return acceptUpdateRequest(request); // 수정 요청 처리 + case DELETE: + return acceptDeleteRequest(request); // 삭제 요청 처리 + default: + throw new AppException(INVALID_REQUEST_TYPE); + } + } + + /** + * 등록 요청 처리 + */ + @Transactional + public SuccessResponse acceptRegisterRequest(Request request) { + // 요청한 향수 정보 조회(등록 -> RequestPerfume에서 조회) + RequestPerfume reqPerfume = request.getRequestPerfume(); + + // 요청한 향수 노트 정보 조회 + List reqPerfumeNotes = requestPerfumeNoteRepository.findByRequestPerfume(reqPerfume); + + // 요청한 브랜드 정보 조회 없다면 기존 브랜드 매핑 + Brand brand = brandRepository.findByName(reqPerfume.getRequestBrand().getName()) + .orElseGet(() -> brandRepository.save( + Brand.builder() + .name(reqPerfume.getRequestBrand().getName()) + .url(reqPerfume.getRequestBrand().getUrl()) + .build() + )); + + // 요청한 향수 정보 저장 또는 기존 향수 매핑 + Perfume perfume = perfumeRepository.findByName(reqPerfume.getName()) + .orElseGet(() -> perfumeRepository.save( + Perfume.builder() + .name(reqPerfume.getName()) + .price(reqPerfume.getPrice()) + .brand(brand) + .build() + )); - return PerfumeDetailResponse.toDto(perfume, notes); + // 요청한 노트 정보 저장 또는 기존 노트 매핑 후 PerfumeNote 저장 + for (RequestPerfumeNote reqPerfumeNote : reqPerfumeNotes) { + Note note = noteRepository.findByName(reqPerfumeNote.getRequestNote().getName()) + .orElseGet(() -> noteRepository.save( + Note.builder() + .name(reqPerfumeNote.getRequestNote().getName()) + .build() + )); + + // PerfumeNote 저장 + perfumeNoteRepository.save( + PerfumeNote.builder() + .perfume(perfume) + .note(note) + .noteType(reqPerfumeNote.getNoteType()) + .build() + ); + } + + // 요청 상태를 승인으로 변경 + request.updateRequestStatus(RequestStatus.APPROVED); + requestRepository.save(request); + + return new SuccessResponse<>(REGISTER_COMPLETED, NoneResponse.NONE); } + /** + * 수락 요청 처리 + */ + @Transactional + public SuccessResponse acceptUpdateRequest(Request request) { + // 기존 향수 정보 조회 + Perfume perfume = request.getPerfume(); // 기존 향수 정보 + // 요청된 향수 정보 조회 + RequestPerfume reqPerfume = request.getRequestPerfume(); // 요청된 향수 정보 + // 기존 브랜드가 있는지 확인 없으면 새로 생성 + Brand brand = brandRepository.findByName(reqPerfume.getRequestBrand().getName()) + .orElseGet(() -> brandRepository.save( + Brand.builder() + .name(reqPerfume.getRequestBrand().getName()) + .url(reqPerfume.getRequestBrand().getUrl()) + .build() + )); + + // 기존 향수의 정보를 요청된 정보로 업데이트 + perfume = Perfume.builder() + .id(perfume.getId()) + .name(reqPerfume.getName()) + .price(reqPerfume.getPrice()) + .brand(brand) + .build(); + + perfumeRepository.save(perfume); + + // 기존 향수와 연결된 모든 PerfumeNote 삭제 + perfumeNoteRepository.deleteByPerfume(perfume); + + // 요청된 노트 정보 처리 + List reqPerfumeNotes = requestPerfumeNoteRepository.findByRequestPerfume(reqPerfume); + for (RequestPerfumeNote reqPerfumeNote : reqPerfumeNotes) { + // 기존 노트가 있으면 사용, 없으면 새로 생성 + Note note = noteRepository.findByName(reqPerfumeNote.getRequestNote().getName()) + .orElseGet(() -> noteRepository.save( + Note.builder() + .name(reqPerfumeNote.getRequestNote().getName()) + .build() + )); + + // PerfumeNote 테이블에 새로운 노트 추가 + perfumeNoteRepository.save( + PerfumeNote.builder() + .perfume(perfume) + .note(note) + .noteType(reqPerfumeNote.getNoteType()) + .build() + ); + } + + // 요청 상태를 승인으로 변경 + request.updateRequestStatus(RequestStatus.APPROVED); + requestRepository.save(request); + + return new SuccessResponse<>(UPDATE_COMPLETED, NoneResponse.NONE); + } + + + /** + * 삭제 요청 처리 + */ + @Transactional + public SuccessResponse acceptDeleteRequest(Request request) { + // 삭제할 향수 정보 조회 + Perfume perfume = request.getPerfume(); + + // 향수-노트 관계 삭제 + List perfumeNotes = perfumeNoteRepository.findByPerfume(perfume); + perfumeNoteRepository.deleteAll(perfumeNotes); + + // 향수 삭제 + perfumeRepository.delete(perfume); + + request.updateRequestStatus(RequestStatus.APPROVED); + requestRepository.save(request); + + return new SuccessResponse<>(DELETE_COMPLETED, NoneResponse.NONE); + } + + + /** + * 요청 거절 + */ + @Transactional + public SuccessResponse rejectPerfumeRequest(Long requestId) { + Request request = requestRepository.findById(requestId) + .orElseThrow(() -> new AppException(REQUEST_NOT_FOUND)); + + // 요청 상태를 거절로 변경 후 저장 + request.updateRequestStatus(RequestStatus.REJECTED); + requestRepository.save(request); + + return new SuccessResponse<>(REJECTED_COMPLETED, NoneResponse.NONE); + } } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/RequestPerfumeService.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/RequestPerfumeService.java index df04e87..e672a0e 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/RequestPerfumeService.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfume/service/RequestPerfumeService.java @@ -1,7 +1,227 @@ package com.perfumepedia.perfumepedia.domain.perfume.service; +import com.perfumepedia.perfumepedia.domain.brand.entity.RequestBrand; +import com.perfumepedia.perfumepedia.domain.brand.repository.RequestBrandRepository; +import com.perfumepedia.perfumepedia.domain.note.entity.NoteType; +import com.perfumepedia.perfumepedia.domain.note.entity.RequestNote; +import com.perfumepedia.perfumepedia.domain.note.repository.RequestNoteRepository; +import com.perfumepedia.perfumepedia.domain.perfume.entity.Perfume; +import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; +import com.perfumepedia.perfumepedia.domain.perfume.repository.PerfumeRepository; +import com.perfumepedia.perfumepedia.domain.perfume.repository.RequestPerfumeRepository; +import com.perfumepedia.perfumepedia.domain.perfumeNote.dto.RequestPerfumeDetailReq; +import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.RequestPerfumeNote; +import com.perfumepedia.perfumepedia.domain.perfumeNote.repository.RequestPerfumeNoteRepository; +import com.perfumepedia.perfumepedia.domain.request.entity.Request; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestStatus; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestType; +import com.perfumepedia.perfumepedia.domain.request.repository.RequestRepository; +import com.perfumepedia.perfumepedia.global.enums.NoneResponse; +import com.perfumepedia.perfumepedia.global.handler.AppException; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +import static com.perfumepedia.perfumepedia.global.enums.ErrorCode.PERFUME_NOT_FOUND; +import static com.perfumepedia.perfumepedia.global.enums.SuccessCode.REQUEST_COMPLETED; @Service public class RequestPerfumeService { + + private final RequestPerfumeRepository requestPerfumeRepository; + private final RequestBrandRepository requestBrandRepository; + private final RequestNoteRepository requestNoteRepository; + private final RequestPerfumeNoteRepository reqPerfumeNoteRepository; + private final RequestRepository requestRepository; + private final PerfumeRepository perfumeRepository; + + @Autowired + public RequestPerfumeService(RequestPerfumeRepository requestPerfumeRepository, RequestBrandRepository requestBrandRepository, + RequestNoteRepository requestNoteRepository, RequestPerfumeNoteRepository reqPerfumeNoteRepository, + RequestRepository requestRepository, PerfumeRepository perfumeRepository) { + this.requestPerfumeRepository = requestPerfumeRepository; + this.requestBrandRepository = requestBrandRepository; + this.requestNoteRepository = requestNoteRepository; + this.reqPerfumeNoteRepository = reqPerfumeNoteRepository; + this.requestRepository = requestRepository; + this.perfumeRepository = perfumeRepository; + } + + + /** + * 향수 등록 요청 api + * + * @param reqPerfumeDetailReq 향수 등록에 필요한 요청 데이터 + * @param userId 요청한 유저의 ID + * @return perfumeDetailReq + */ + public SuccessResponse registerPerfumeRequest(RequestPerfumeDetailReq reqPerfumeDetailReq, Long userId) { + // 요청 브랜드에 저장 + RequestBrand reqBrand = saveReqBrand(reqPerfumeDetailReq.getBrand()); + + // 요청 향수에 저장 + RequestPerfume reqPerfume = saveReqPerfume(reqPerfumeDetailReq.getName(), reqPerfumeDetailReq.getPrice(), reqBrand); + + // 요청 노트 & 요청 퍼퓸 노트 저장 + saveNotes(reqPerfumeDetailReq, reqPerfume); + + // 요청 저장 + Request request = Request.builder() + .requestType(RequestType.CREATE) // 등록 요청 + .requestStatus(RequestStatus.PENDING) // 대기중 + .userId(userId) + .requestPerfume(reqPerfume) // 등록 요청 상태인 향수 정보 + .build(); + + requestRepository.save(request); + + // 반환 데이터 없음 + return new SuccessResponse<>(REQUEST_COMPLETED, NoneResponse.NONE); + } + + /** + * 향수 수정 요청 api + * + * @param reqPerfumeDetailReq 수정할 향수의 정보 + * @param perfume 수정할 향수의 ID + * @param userId 수정 요청한 유저의 ID + **/ + public SuccessResponse updatePerfumeRequest(RequestPerfumeDetailReq reqPerfumeDetailReq, Long perfume, Long userId) { + // 기존 향수 조회 + Perfume originPerfume = perfumeRepository.findById(perfume) + .orElseThrow(() -> new AppException(PERFUME_NOT_FOUND)); + + // 요청 브랜드에 저장 + RequestBrand reqBrand = saveReqBrand(reqPerfumeDetailReq.getBrand()); + + // 요청 향수에 저장 + RequestPerfume reqPerfume = saveReqPerfume(reqPerfumeDetailReq.getName(), reqPerfumeDetailReq.getPrice(), reqBrand); + + // 요청 노트 & 요청 퍼퓸 노트 저장 + saveNotes(reqPerfumeDetailReq, reqPerfume); + + + Request request = Request.builder() + .requestType(RequestType.UPDATE) // 수정 요청 + .requestStatus(RequestStatus.PENDING) // 대기중 + .userId(userId) + .requestPerfume(reqPerfume) // 수정 요청 된 향수 + .perfume(originPerfume) // 기존 향수 + .build(); + + return new SuccessResponse<>(REQUEST_COMPLETED, NoneResponse.NONE); + + + } + + /** + * 향수 삭제 요청 api + * + * @param perfumeId 삭제할 향수의 ID + * @param userId 삭제 요청한 유저의 ID + **/ + public SuccessResponse deletePerfumeRequest(Long perfumeId, Long userId) { + Perfume perfume = perfumeRepository.findById(perfumeId) + .orElseThrow(() -> new AppException(PERFUME_NOT_FOUND)); + + Request request = Request.builder() + .requestType(RequestType.DELETE) // 삭제 요청 + .requestStatus(RequestStatus.PENDING) // 대기중 + .userId(userId) + .perfume(perfume) // 기존 향수 + .build(); + + + return new SuccessResponse<>(REQUEST_COMPLETED, NoneResponse.NONE); + } + + + /** + * RequestPerfumeNote에 저장하는 메소드 + * + * @param perfume 요청 향수정보 + * @param requestNote 요청 노트 정보 + * @param type 노트 타입 + */ + private void savePerfumeNote(RequestPerfume perfume, RequestNote requestNote, NoteType type) { + RequestPerfumeNote perfumeNote = RequestPerfumeNote.builder() + .requestPerfume(perfume) + .requestNote(requestNote) + .noteType(type) + .build(); + // PerfumeNote 저장 + reqPerfumeNoteRepository.save(perfumeNote); + } + + /** + * 노트의 타입별로 저장하는 메서드 + * + * @param dto 요청된 모든 정보 + * @param Perfume 요청 향수 정보 + */ + private void saveNotes(RequestPerfumeDetailReq dto, RequestPerfume Perfume) { + saveNotesAndReqPerfumeNote(dto.getTopNote(), Perfume, NoteType.TOP); + saveNotesAndReqPerfumeNote(dto.getMiddleNote(), Perfume, NoteType.MIDDLE); + saveNotesAndReqPerfumeNote(dto.getBaseNote(), Perfume, NoteType.BASE); + saveNotesAndReqPerfumeNote(dto.getSingleNote(), Perfume, NoteType.SINGLE); + } + + + /** + * 노트 리스트를 분리하여 각각의 노트들을 저장 &

+ * RequestPerfumeNote에 저장하는 메서드 + * + * @param notes 노트 정보 + * @param reqPerfume 요청 향수 정보 + * @param type 노트 타입 + */ + private void saveNotesAndReqPerfumeNote(String notes, RequestPerfume reqPerfume, NoteType type) { + + if (notes != null && !notes.isEmpty()) { + String[] noteList = notes.split(","); // ,기준으로 노트를 분리 + for (String rawNote : noteList) { + String note = rawNote.trim(); // 분리된 노트 앞뒤 공백 제거 + if (!note.isEmpty()) { + // RequestNote 저장 + RequestNote reqNote = requestNoteRepository.findByName(note) + .orElseGet(() -> requestNoteRepository.save( + RequestNote.builder() + .name(note) + .build()) + ); + // RequestPerfumeNote 저장 + savePerfumeNote(reqPerfume, reqNote, type); + } + } + } + } + + // 요청 브렌드를 저장 후 반환 + @Transactional + public RequestBrand saveReqBrand(String brandName) { + + RequestBrand newBrand = RequestBrand.builder() + .name(brandName) + .url(null) // 임시 처리 + .build(); + + return requestBrandRepository.save(newBrand); + } + + // 요청 향수를 저장 후 반환 + @Transactional + public RequestPerfume saveReqPerfume(String name, int price, RequestBrand requestBrand) { + + RequestPerfume perfume = RequestPerfume.builder() + .name(name) + .price(price) + .requestBrand(requestBrand) + .build(); + + return requestPerfumeRepository.save(perfume); + } + + } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/PerfumeDetailResponse.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/PerfumeDetailResponse.java index 27bf57d..9ca8790 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/PerfumeDetailResponse.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/PerfumeDetailResponse.java @@ -1,9 +1,8 @@ package com.perfumepedia.perfumepedia.domain.perfumeNote.dto; import com.perfumepedia.perfumepedia.domain.perfume.entity.Perfume; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; + import java.util.List; import java.util.Map; @@ -16,7 +15,7 @@ public record PerfumeDetailResponse( Map> notes, int price ) { - // Entity -> DTO + // Entity -> DTO (기존 향수) public static PerfumeDetailResponse toDto(Perfume perfume, Map> notes) { return new PerfumeDetailResponse( perfume.getId(), @@ -26,4 +25,15 @@ public static PerfumeDetailResponse toDto(Perfume perfume, Map DTO (신규 향수) + public static PerfumeDetailResponse fromEntity(RequestPerfume requestPerfume, Map> notes) { + return new PerfumeDetailResponse( + requestPerfume.getId(), + requestPerfume.getName(), + requestPerfume.getRequestBrand().getName(), + notes, + requestPerfume.getPrice() + ); + } } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/PerfumeNoteUpdateReq.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/PerfumeNoteUpdateReq.java deleted file mode 100644 index d8c3865..0000000 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/PerfumeNoteUpdateReq.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.perfumepedia.perfumepedia.domain.perfumeNote.dto; - -import com.perfumepedia.perfumepedia.domain.note.entity.Note; -import com.perfumepedia.perfumepedia.domain.note.entity.NoteType; -import com.perfumepedia.perfumepedia.domain.perfume.entity.Perfume; -import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.PerfumeNote; -import lombok.Builder; - -public record PerfumeNoteUpdateReq(Long id, Long perfumeId, String perfumeName, Long noteId, String noteName, - String noteType) { - - @Builder - public PerfumeNoteUpdateReq(Long id, Long perfumeId, String perfumeName, Long noteId, String noteName, String noteType) { - this.id = id; - this.perfumeId = perfumeId; - this.perfumeName = perfumeName; - this.noteId = noteId; - this.noteName = noteName; - this.noteType = noteType; - } - - // Entity -> DTO - public static PerfumeNoteUpdateReq toDto(PerfumeNote perfumeNote) { - return PerfumeNoteUpdateReq.builder() - .id(perfumeNote.getId()) - .perfumeId(perfumeNote.getPerfume().getId()) - .perfumeName(perfumeNote.getPerfume().getName()) - .noteId(perfumeNote.getNote().getId()) - .noteName(perfumeNote.getNote().getName()) - .noteType(perfumeNote.getNoteType().name()) - .build(); - } - - // DTO -> Entity - public PerfumeNote toEntity(Perfume perfume, Note note) { - return PerfumeNote.builder() - .id(this.id) - .perfume(perfume) - .note(note) - .noteType(NoteType.valueOf(this.noteType)) // Enum으로 변환 - .build(); - } -} diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/RequestPerfumeDetailReq.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/RequestPerfumeDetailReq.java new file mode 100644 index 0000000..daf518e --- /dev/null +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/RequestPerfumeDetailReq.java @@ -0,0 +1,29 @@ +package com.perfumepedia.perfumepedia.domain.perfumeNote.dto; + +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class RequestPerfumeDetailReq { + + private String name; // 향수 이름 + private String brand; // 브랜드 이름 + private String topNote; // 탑 노트 + private String middleNote; // 미들 노트 + private String baseNote; // 베이스 노트 + private String singleNote; // 싱글 노트 + private int price; // 가격 + + @Builder + public RequestPerfumeDetailReq(String name, String brand, String topNote, String middleNote, String baseNote, String singleNote, int price) { + this.name = name; + this.brand = brand; + this.topNote = topNote; + this.middleNote = middleNote; + this.baseNote = baseNote; + this.singleNote = singleNote; + this.price = price; + } +} diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/RequestPerfumeNoteUpdateReq.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/RequestPerfumeNoteUpdateReq.java deleted file mode 100644 index 1528d00..0000000 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/dto/RequestPerfumeNoteUpdateReq.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.perfumepedia.perfumepedia.domain.perfumeNote.dto; - -import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.RequestPerfumeNote; -import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; -import com.perfumepedia.perfumepedia.domain.note.entity.RequestNote; -import com.perfumepedia.perfumepedia.domain.note.entity.NoteType; -import lombok.Builder; - -public record RequestPerfumeNoteUpdateReq(Long id, Long requestPerfumeId, String requestPerfumeName, - Long requestNoteId, String requestNoteName, String noteType) { - - @Builder - public RequestPerfumeNoteUpdateReq(Long id, Long requestPerfumeId, String requestPerfumeName, - Long requestNoteId, String requestNoteName, String noteType) { - this.id = id; - this.requestPerfumeId = requestPerfumeId; - this.requestPerfumeName = requestPerfumeName; - this.requestNoteId = requestNoteId; - this.requestNoteName = requestNoteName; - this.noteType = noteType; - } - - // Entity -> DTO - public static RequestPerfumeNoteUpdateReq toDto(RequestPerfumeNote requestPerfumeNote) { - return RequestPerfumeNoteUpdateReq.builder() - .id(requestPerfumeNote.getId()) - .requestPerfumeId(requestPerfumeNote.getRequestPerfume().getId()) - .requestPerfumeName(requestPerfumeNote.getRequestPerfume().getName()) // RequestPerfume에서 name을 가져옴 - .requestNoteId(requestPerfumeNote.getRequestNote().getId()) - .requestNoteName(requestPerfumeNote.getRequestNote().getName()) // RequestNote에서 name을 가져옴 - .noteType(requestPerfumeNote.getNoteType().name()) // String으로 변환 - .build(); - } - - // DTO -> Entity - public RequestPerfumeNote toEntity(RequestPerfume requestPerfume, RequestNote requestNote) { - return RequestPerfumeNote.builder() - .id(this.id) - .requestPerfume(requestPerfume) - .requestNote(requestNote) - .noteType(NoteType.valueOf(this.noteType)) // Enum으로 변환 - .build(); - } -} diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/PerfumeNoteRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/PerfumeNoteRepository.java index 1f59268..9fb4941 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/PerfumeNoteRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/PerfumeNoteRepository.java @@ -1,5 +1,7 @@ package com.perfumepedia.perfumepedia.domain.perfumeNote.repository; +import com.perfumepedia.perfumepedia.domain.note.entity.Note; +import com.perfumepedia.perfumepedia.domain.perfume.entity.Perfume; import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.PerfumeNote; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -8,8 +10,15 @@ @Repository public interface PerfumeNoteRepository extends JpaRepository { - List findByNoteContaining(String keyword); + List findByNote_NameContaining(String keyword); List findByPerfumeId(Long perfumeId); + List findByPerfume(Perfume Perfume); + + void deleteByPerfume(Perfume perfume); + + + + } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/RequestPerfumeNoteRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/RequestPerfumeNoteRepository.java index dec6c74..a46e0ce 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/RequestPerfumeNoteRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/repository/RequestPerfumeNoteRepository.java @@ -1,7 +1,16 @@ package com.perfumepedia.perfumepedia.domain.perfumeNote.repository; +import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; +import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.QRequestPerfumeNote; import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.RequestPerfumeNote; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface RequestPerfumeNoteRepository extends JpaRepository { -} + + List findByRequestPerfumeId(Long requestPerfumeId); + + List findByRequestPerfume(RequestPerfume requestPerfume); + +} \ No newline at end of file diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/service/RequestPerfumeNoteService.java b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/service/RequestPerfumeNoteService.java index e51b6d1..7cc4de6 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/service/RequestPerfumeNoteService.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/perfumeNote/service/RequestPerfumeNoteService.java @@ -1,4 +1,116 @@ package com.perfumepedia.perfumepedia.domain.perfumeNote.service; +import com.perfumepedia.perfumepedia.domain.perfume.entity.Perfume; +import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; +import com.perfumepedia.perfumepedia.domain.perfumeNote.dto.PerfumeDetailResponse; +import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.PerfumeNote; +import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.RequestPerfumeNote; +import com.perfumepedia.perfumepedia.domain.perfumeNote.repository.PerfumeNoteRepository; +import com.perfumepedia.perfumepedia.domain.perfumeNote.repository.RequestPerfumeNoteRepository; +import com.perfumepedia.perfumepedia.domain.request.entity.Request; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestType; +import com.perfumepedia.perfumepedia.domain.request.repository.RequestRepository; +import com.perfumepedia.perfumepedia.global.handler.AppException; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.perfumepedia.perfumepedia.global.enums.ErrorCode.*; +import static com.perfumepedia.perfumepedia.global.enums.SuccessCode.SEARCH_COMPLETED; + +@Service public class RequestPerfumeNoteService { + + private final RequestRepository requestRepository; + private final RequestPerfumeNoteRepository requestPerfumeNoteRepository; + private final PerfumeNoteRepository PerfumeNoteRepository; + + + public RequestPerfumeNoteService(RequestRepository requestRepository, RequestPerfumeNoteRepository requestPerfumeNoteRepository, PerfumeNoteRepository PerfumeNoteRepository) { + this.requestRepository = requestRepository; + this.requestPerfumeNoteRepository = requestPerfumeNoteRepository; + this.PerfumeNoteRepository = PerfumeNoteRepository; + } + + /** + * 등록 요청 / 수정 요청 상세 조회 + */ + public SuccessResponse getRegisterRequestDetail(Long requestId, String requestType) { + RequestType type = RequestType.valueOf(requestType.toUpperCase()); + + // 요청 조회 + Request registerRequest = requestRepository.findById(requestId) + .orElseThrow(() -> new AppException(REQUEST_NOT_FOUND)); + + if (registerRequest.getRequestType() != type) { + throw new AppException(REQUEST_TYPE_MISMATCH); + } + + // 요청한 향수 정보 (RequestPerfume에서 id 받아옴) + RequestPerfume requestPerfume = registerRequest.getRequestPerfume(); + + // 요청한 향수 노트 정보 + List requestPerfumeNotes = requestPerfumeNoteRepository.findByRequestPerfumeId(requestPerfume.getId()); + + if (requestPerfumeNotes.isEmpty()) { + throw new AppException(NOTE_NOT_FOUND); + } + + Map> notes = new HashMap<>(); + for (RequestPerfumeNote requestPerfumeNote : requestPerfumeNotes) { + String noteType = requestPerfumeNote.getNoteType().name(); + if (!notes.containsKey(noteType)) { + notes.put(noteType, new ArrayList<>()); + } + notes.get(noteType).add(requestPerfumeNote.getRequestNote().getName()); + } + + // entity -> dto + PerfumeDetailResponse detailPerfume = PerfumeDetailResponse.fromEntity(requestPerfume, notes); + return new SuccessResponse<>(SEARCH_COMPLETED, detailPerfume); + } + + /** + * 삭제 요청 / 수정 요청 상세 조회 + */ + public SuccessResponse getDeleteRequestDetail(Long requestId, String requestType) { + + RequestType type = RequestType.valueOf(requestType.toUpperCase()); + + // 요청 조회 + Request deleteRequest = requestRepository.findById(requestId) + .orElseThrow(() -> new AppException(REQUEST_NOT_FOUND)); + + // 요청 타입 검증 + if (deleteRequest.getRequestType() != type) { + throw new AppException(REQUEST_TYPE_MISMATCH); + } + + // 요청한 향수 정보 (Perfume에서 id 받아옴) + Perfume perfume = deleteRequest.getPerfume(); + + // 요청한 향수 노트 정보 + List perfumeNotes = PerfumeNoteRepository.findByPerfumeId(perfume.getId()); + if (perfumeNotes.isEmpty()) { + throw new AppException(NOTE_NOT_FOUND); + } + + Map> notes = new HashMap<>(); + for (PerfumeNote perfumeNote : perfumeNotes) { + String noteType = perfumeNote.getNoteType().name(); + + if (!notes.containsKey(noteType)) { + notes.put(noteType, new ArrayList<>()); + } + notes.get(noteType).add(perfumeNote.getNote().getName()); + } + // entity -> dto + PerfumeDetailResponse detailPerfume = PerfumeDetailResponse.toDto(perfume, notes); + + return new SuccessResponse<>(SEARCH_COMPLETED, detailPerfume); + } } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/request/controller/RequestController.java b/src/main/java/com/perfumepedia/perfumepedia/domain/request/controller/RequestController.java new file mode 100644 index 0000000..f2cc48d --- /dev/null +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/request/controller/RequestController.java @@ -0,0 +1,159 @@ +package com.perfumepedia.perfumepedia.domain.request.controller; + +import com.perfumepedia.perfumepedia.domain.perfume.service.PerfumeService; +import com.perfumepedia.perfumepedia.domain.perfume.service.RequestPerfumeService; +import com.perfumepedia.perfumepedia.domain.perfumeNote.dto.PerfumeDetailResponse; +import com.perfumepedia.perfumepedia.domain.perfumeNote.dto.RequestPerfumeDetailReq; +import com.perfumepedia.perfumepedia.domain.perfumeNote.service.RequestPerfumeNoteService; +import com.perfumepedia.perfumepedia.domain.request.dto.RequestListDto; +import com.perfumepedia.perfumepedia.domain.request.service.RequestService; +import com.perfumepedia.perfumepedia.global.enums.NoneResponse; +import com.perfumepedia.perfumepedia.global.response.Response; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@Tag(name = "향수 요청", description = "향수 요청 관련 API") + +public class RequestController { + + private final RequestPerfumeService requestPerfumeService; + private final RequestService requestService; + private final RequestPerfumeNoteService requestPerfumeNoteService; + private final PerfumeService perfumeService; + + @Autowired + public RequestController(RequestPerfumeService requestPerfumeService, RequestService requestService, + RequestPerfumeNoteService requestPerfumeNoteService, PerfumeService perfumeService) { + this.requestPerfumeService = requestPerfumeService; + this.requestService = requestService; + this.requestPerfumeNoteService = requestPerfumeNoteService; + this.perfumeService = perfumeService; + + } + + /** + * 향수 등록 요청 api + */ + @PostMapping("/perfumes/users") + public ResponseEntity> registerPerfumeRequest( + @RequestBody RequestPerfumeDetailReq reqPerfumeDetailReq +// @AuthenticationPrincipal Long userId + ) { + SuccessResponse response = requestPerfumeService.registerPerfumeRequest(reqPerfumeDetailReq, 1L); + return Response.success(response); + } + + + /** + * 향수 수정 요청 api + */ + @PostMapping("/perfumes/users/{perfumeId}/update") + public ResponseEntity> updatePerfumeRequest( + @RequestBody RequestPerfumeDetailReq reqPerfumeDetailReq, + @PathVariable Long perfumeId +// @AuthenticationPrincipal Long userId + ) { + SuccessResponse response = requestPerfumeService.updatePerfumeRequest(reqPerfumeDetailReq, perfumeId, 1L); + return Response.success(response); + } + + /** + * 향수 삭제 요청 api + */ + @PostMapping("/perfumes/users/{perfumeId}/delete") + public ResponseEntity> deletePerfumeRequest( + @PathVariable Long perfumeId +// @AuthenticationPrincipal Long userId + ) { + SuccessResponse response = requestPerfumeService.deletePerfumeRequest(perfumeId, 1L); + return Response.success(response); + } + + /** + * 향수 요청 개수 조회 api + */ + @GetMapping("/perfumes/admins/request-counts") + public ResponseEntity>> getRequestCounts() { + SuccessResponse> response = requestService.getRequestCount(); + return Response.success(response); + } + + /** + * 등록 요청 목록 조회 + */ + @GetMapping("/perfumes/admins/requests/register") + public ResponseEntity>> getRegisterRequests() { + SuccessResponse> response = requestService.getRegisterRequests(); + return Response.success(response); + } + + /** + * 수정 요청 목록 조회 + */ + @GetMapping("/perfumes/admins/requests/update") + public ResponseEntity>> getUpdateRequests() { + SuccessResponse> response = requestService.getUpdateRequests(); + return Response.success(response); + } + + /** + * 삭제 요청 목록 조회 + */ + @GetMapping("/perfumes/admins/requests/delete") + public ResponseEntity>> getDeleteRequests() { + SuccessResponse> response = requestService.getDeleteRequests(); + return Response.success(response); + } + + /** + * 신규 향수 상세 조회 (등록, 수정) + */ + @GetMapping("/perfumes/admins/register/{perfumeId}") + public ResponseEntity> getRegisterRequestDetail( + @RequestParam String requestType, + @PathVariable Long perfumeId + ) { + SuccessResponse response = requestPerfumeNoteService.getRegisterRequestDetail(perfumeId, requestType); + return Response.success(response); + } + + /** + * 기존 요청 상세 조회(삭제, 수정) + */ + @GetMapping("/perfumes/admins/update/{perfumeId}") + public ResponseEntity> getUpdateRequestDetail( + @RequestParam String requestType, + @PathVariable Long perfumeId + ) { + SuccessResponse response = requestPerfumeNoteService.getDeleteRequestDetail(perfumeId, requestType); + return Response.success(response); + } + + + /** + * 요청 수락 API + */ + @PostMapping("/perfumes/admins/{requestId}/accept") + public ResponseEntity> acceptPerfumeRequest(@PathVariable Long requestId) { + SuccessResponse response = perfumeService.acceptPerfumeRequest(requestId); + return Response.success(response); + } + + /** + * 요청 거절 API + */ + @PostMapping("/perfumes/admins/{requestId}/reject") + public ResponseEntity> rejectPerfumeRequest(@PathVariable Long requestId) { + SuccessResponse response = perfumeService.rejectPerfumeRequest(requestId); + return Response.success(response); + } + +} diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/request/dto/RequestListDto.java b/src/main/java/com/perfumepedia/perfumepedia/domain/request/dto/RequestListDto.java new file mode 100644 index 0000000..cdfff4f --- /dev/null +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/request/dto/RequestListDto.java @@ -0,0 +1,26 @@ +package com.perfumepedia.perfumepedia.domain.request.dto; + +import com.perfumepedia.perfumepedia.domain.request.entity.RequestType; +import lombok.Builder; +import lombok.Getter; + +@Getter +public class RequestListDto { + + private Long perfumeId; + private String perfumeName; + + + @Builder + public RequestListDto(Long perfumeId, String perfumeName) { + this.perfumeId = perfumeId; + this.perfumeName = perfumeName; + } + + + + + +} + + diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/request/dto/RequestUpdateReq.java b/src/main/java/com/perfumepedia/perfumepedia/domain/request/dto/RequestUpdateReq.java deleted file mode 100644 index 82a0b6d..0000000 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/request/dto/RequestUpdateReq.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.perfumepedia.perfumepedia.domain.request.dto; - -import com.perfumepedia.perfumepedia.domain.request.entity.Request; -import com.perfumepedia.perfumepedia.domain.request.entity.RequestStatus; -import com.perfumepedia.perfumepedia.domain.request.entity.RequestType; -import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.PerfumeNote; -import lombok.Builder; - -public record RequestUpdateReq( - Long id, - String type, - String status, - String userName, - Long requestPerfumeNoteId, - Long perfumeNoteId) { - - @Builder - public RequestUpdateReq { - } - - // Entity -> DTO 변환 메서드 - public static RequestUpdateReq toDto(Request request) { - return RequestUpdateReq.builder() - .id(request.getId()) - .type(request.getRequestType().toString()) - .status(request.getRequestStatus().toString()) -// .userName(request.getUser().getNickname()); // 유저 도메인없음 - .requestPerfumeNoteId(request.getRequestPerfumeNote().getId()) - .perfumeNoteId(request.getPerfumeNote() != null ? request.getPerfumeNote().getId() : null) - .build(); - } - -// DTO -> Entity 변환 메서드 -// public Request toEntity(RequestPerfumeNote requestPerfumeNote, PerfumeNote perfumeNote, User user) { -// return Request.builder() -// .id(this.id) -// .requestType(RequestType.valueOf(this.type)) // Enum으로 변환 -// .requestStatus(RequestStatus.valueOf(this.status)) // Enum으로 변환 -// .user(user) // 유저 도메인없음 -// .requestPerfumeNote(requestPerfumeNote) -// .perfumeNote(perfumeNote) -// .build(); -// } -} diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/request/entity/Request.java b/src/main/java/com/perfumepedia/perfumepedia/domain/request/entity/Request.java index 272748f..e678c3b 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/request/entity/Request.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/request/entity/Request.java @@ -1,5 +1,7 @@ package com.perfumepedia.perfumepedia.domain.request.entity; +import com.perfumepedia.perfumepedia.domain.perfume.entity.Perfume; +import com.perfumepedia.perfumepedia.domain.perfume.entity.RequestPerfume; import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.PerfumeNote; import com.perfumepedia.perfumepedia.domain.perfumeNote.entity.RequestPerfumeNote; import com.perfumepedia.perfumepedia.global.entity.BaseEntity; @@ -29,22 +31,26 @@ public class Request extends BaseEntity { // 요청한 향수에 대한 정보 @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "REQUEST_PERFUME_NOTE_ID", nullable = false) - private RequestPerfumeNote requestPerfumeNote; + @JoinColumn(name = "REQUEST_PERFUME_NOTE_ID") + private RequestPerfume requestPerfume; // 수정, 삭제 요청시 이전 향수에 대한 정보 @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "PERFUME_NOTE_ID") - private PerfumeNote perfumeNote; + private Perfume perfume; @Builder public Request(Long id, RequestType requestType, RequestStatus requestStatus, Long userId, - RequestPerfumeNote requestPerfumeNote, PerfumeNote perfumeNote) { + RequestPerfume requestPerfume, Perfume perfume) { this.id = id; this.requestType = requestType; this.requestStatus = requestStatus; this.userId = userId; - this.requestPerfumeNote = requestPerfumeNote; - this.perfumeNote = perfumeNote; + this.requestPerfume = requestPerfume; + this.perfume = perfume; + } + + public void updateRequestStatus(RequestStatus newStatus) { + this.requestStatus = newStatus; } } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/request/repository/RequestRepository.java b/src/main/java/com/perfumepedia/perfumepedia/domain/request/repository/RequestRepository.java index 53bdcb0..f20fab4 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/request/repository/RequestRepository.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/request/repository/RequestRepository.java @@ -1,7 +1,21 @@ package com.perfumepedia.perfumepedia.domain.request.repository; import com.perfumepedia.perfumepedia.domain.request.entity.Request; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestStatus; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestType; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; +import java.util.Optional; + public interface RequestRepository extends JpaRepository { + + // 요청이 없을 경우 0을 반환 + long countByRequestTypeAndRequestStatus(RequestType requestType, RequestStatus requestStatus); + + List findByRequestTypeAndRequestStatus(RequestType requestType, RequestStatus requestStatus); + + Optional findByIdAndRequestType(Long id, RequestType requestType); + + } diff --git a/src/main/java/com/perfumepedia/perfumepedia/domain/request/service/RequestService.java b/src/main/java/com/perfumepedia/perfumepedia/domain/request/service/RequestService.java index 226f5ea..6c9e745 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/domain/request/service/RequestService.java +++ b/src/main/java/com/perfumepedia/perfumepedia/domain/request/service/RequestService.java @@ -1,8 +1,92 @@ package com.perfumepedia.perfumepedia.domain.request.service; +import com.perfumepedia.perfumepedia.domain.request.dto.RequestListDto; +import com.perfumepedia.perfumepedia.domain.request.entity.Request; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestStatus; +import com.perfumepedia.perfumepedia.domain.request.entity.RequestType; +import com.perfumepedia.perfumepedia.domain.request.repository.RequestRepository; +import com.perfumepedia.perfumepedia.global.response.SuccessResponse; import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.perfumepedia.perfumepedia.global.enums.SuccessCode.REQUEST_COMPLETED; + @Service public class RequestService { + private final RequestRepository requestRepository; + + public RequestService(RequestRepository requestRepository) { + this.requestRepository = requestRepository; + } + + /** + * 요청 타입별 요청 개수 조회 + */ + public SuccessResponse> getRequestCount() { + Map requestCount = new HashMap<>(); + requestCount.put("CREATE", requestRepository.countByRequestTypeAndRequestStatus(RequestType.CREATE, RequestStatus.PENDING)); + requestCount.put("UPDATE", requestRepository.countByRequestTypeAndRequestStatus(RequestType.UPDATE, RequestStatus.PENDING)); + requestCount.put("DELETE", requestRepository.countByRequestTypeAndRequestStatus(RequestType.DELETE, RequestStatus.PENDING)); + + return new SuccessResponse<>(REQUEST_COMPLETED, requestCount); + } + + /** + * 등록 요청 조회 + * */ + public SuccessResponse> getRegisterRequests() { + return getRequests(RequestType.CREATE); + } + + /** + * 수정 요청 조회 + * */ + public SuccessResponse> getUpdateRequests() { + return getRequests(RequestType.UPDATE); + } + + /** + * 삭제 요청 조회 + * */ + public SuccessResponse> getDeleteRequests() { + return getRequests(RequestType.DELETE); + } + + /** + * 요청 타입별 요청 조회 후 RequestListDto에 저장

+ * 등록 요청 - RequestPerfume 에서 받아옴

+ * 수정, 삭제 요청 - Perfume 에서 받아옴 + * */ + public SuccessResponse> getRequests(RequestType requestType) { + List requests = requestRepository.findByRequestTypeAndRequestStatus(requestType, RequestStatus.PENDING); + List requestList = new ArrayList<>(); + + for (Request request : requests) { + Long perfumeId = null; + String perfumeName = null; + + if (requestType == RequestType.CREATE) { + perfumeId = request.getRequestPerfume().getId(); + perfumeName = request.getRequestPerfume().getName(); + } else { + perfumeId = request.getPerfume().getId(); + perfumeName = request.getPerfume().getName(); + } + + RequestListDto requestDto = RequestListDto.builder() + .perfumeId(perfumeId) + .perfumeName(perfumeName) + .build(); + + requestList.add(requestDto); + } + + return new SuccessResponse<>(REQUEST_COMPLETED, requestList); + } + } diff --git a/src/main/java/com/perfumepedia/perfumepedia/global/enums/ErrorCode.java b/src/main/java/com/perfumepedia/perfumepedia/global/enums/ErrorCode.java index 3d1fb2f..3af5882 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/global/enums/ErrorCode.java +++ b/src/main/java/com/perfumepedia/perfumepedia/global/enums/ErrorCode.java @@ -17,7 +17,12 @@ public enum ErrorCode implements ResponseCode { // 향수 검색 관련 Error Code PERFUME_NOT_FOUND(HttpStatus.NOT_FOUND, "일치하는 향수가 업서용."), - NOTE_NOT_FOUND(HttpStatus.NOT_FOUND, "일치하는 노트가 없습니다."); + NOTE_NOT_FOUND(HttpStatus.NOT_FOUND, "일치하는 노트가 없습니다."), + REQUEST_NOT_FOUND(HttpStatus.NOT_FOUND, "요청이 존재하지 않습니다."), + + // DTO 관련 + INVALID_REQUEST_TYPE(HttpStatus.BAD_REQUEST, "요청 타입이 잘못되었습니다."), + REQUEST_TYPE_MISMATCH(HttpStatus.BAD_REQUEST, "요청 타입이 일치하지 않습니다."); diff --git a/src/main/java/com/perfumepedia/perfumepedia/global/enums/SuccessCode.java b/src/main/java/com/perfumepedia/perfumepedia/global/enums/SuccessCode.java index 02b71b8..380a361 100644 --- a/src/main/java/com/perfumepedia/perfumepedia/global/enums/SuccessCode.java +++ b/src/main/java/com/perfumepedia/perfumepedia/global/enums/SuccessCode.java @@ -9,7 +9,21 @@ public enum SuccessCode implements ResponseCode { // BASE API - SUCCESS(HttpStatus.OK, "Retrieval completed successfully."); + SUCCESS(HttpStatus.OK, "Retrieval completed successfully."), + + // 검색 관련 + SEARCH_COMPLETED(HttpStatus.OK, "검색이 성공적으로 이루어졌습니다."), + + // 요청 관련 + REQUEST_COMPLETED(HttpStatus.OK, "요청이 성공적으로 이루어졌습니다."), + + // 향수 등록 관련 + REGISTER_COMPLETED(HttpStatus.OK, "향수 등록이 성공적으로 이루어졌습니다."), + REJECTED_COMPLETED(HttpStatus.OK, "향수 등록이 거절되었습니다."), + DELETE_COMPLETED(HttpStatus.OK, "향수 삭제가 성공적으로 이루어졌습니다."), + UPDATE_COMPLETED(HttpStatus.OK, "향수 수정이 성공적으로 이루어졌습니다."); + + private final HttpStatus httpStatus; private final String message;