From 9a97ce8454ce3e76bd24af2fa1ea80ae9be72455 Mon Sep 17 00:00:00 2001 From: kwonhee1 Date: Sat, 11 Oct 2025 15:24:47 +0900 Subject: [PATCH 1/2] feat admin controller --- .../admin/project/AdminProjectController.java | 37 ++++++++++++++++ .../admin/project/AdminProjectService.java | 36 +++++++++++++++ .../demo/admin/user/AdminUserController.java | 29 ++++++++++++ .../demo/admin/user/AdminUserService.java | 37 ++++++++++++++++ .../project/project/entity/ProjectEntity.java | 1 + .../project/service/ProjectDeleteService.java | 44 +++++++++++++++++++ .../project/service/ProjectService.java | 21 --------- .../project/service/ProjectStatusService.java | 26 +++++++++++ 8 files changed, 210 insertions(+), 21 deletions(-) create mode 100644 src/main/java/NextLevel/demo/admin/project/AdminProjectController.java create mode 100644 src/main/java/NextLevel/demo/admin/project/AdminProjectService.java create mode 100644 src/main/java/NextLevel/demo/admin/user/AdminUserController.java create mode 100644 src/main/java/NextLevel/demo/admin/user/AdminUserService.java create mode 100644 src/main/java/NextLevel/demo/project/project/service/ProjectDeleteService.java create mode 100644 src/main/java/NextLevel/demo/project/project/service/ProjectStatusService.java diff --git a/src/main/java/NextLevel/demo/admin/project/AdminProjectController.java b/src/main/java/NextLevel/demo/admin/project/AdminProjectController.java new file mode 100644 index 0000000..9e20a36 --- /dev/null +++ b/src/main/java/NextLevel/demo/admin/project/AdminProjectController.java @@ -0,0 +1,37 @@ +package NextLevel.demo.admin.project; + +import NextLevel.demo.common.SuccessResponse; +import NextLevel.demo.project.project.service.ProjectDeleteService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/admin/project") +public class AdminProjectController { + + private final ProjectDeleteService projectDeleteService; + private final AdminProjectService adminProjectService; + + public ResponseEntity getProjectList() { + return null; + } + + public ResponseEntity updateProjectStatus() { + return null; + } + + public ResponseEntity updateProject() { + return null; + } + + @DeleteMapping("/{projectId}") + public ResponseEntity removeProject(@PathVariable("projectId") Long projectId) { + projectDeleteService.deleteProject(projectId, null); + return ResponseEntity.ok().body(new SuccessResponse("success", null)); + } +} diff --git a/src/main/java/NextLevel/demo/admin/project/AdminProjectService.java b/src/main/java/NextLevel/demo/admin/project/AdminProjectService.java new file mode 100644 index 0000000..0239313 --- /dev/null +++ b/src/main/java/NextLevel/demo/admin/project/AdminProjectService.java @@ -0,0 +1,36 @@ +package NextLevel.demo.admin.project; + +import NextLevel.demo.project.ProjectStatus; +import NextLevel.demo.project.project.service.ProjectDeleteService; +import NextLevel.demo.project.project.service.ProjectService; +import NextLevel.demo.project.project.service.ProjectStatusService; +import NextLevel.demo.project.project.service.ProjectValidateService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class AdminProjectService { + + private final ProjectService projectService; + private final ProjectDeleteService projectDeleteService; + private final ProjectStatusService projectStatusService; + private final ProjectValidateService projectValidateService; + + public void getProjectList() { + + } + + public void updateProjectStatus(Long projectId, ProjectStatus status) { + projectStatusService.updateProjectStatus(projectId, status, "by admin"); + } + + public void updateProject() { + + } + + public void removeProject(Long projectId) { + projectDeleteService.deleteProject(projectId, null); + } + +} diff --git a/src/main/java/NextLevel/demo/admin/user/AdminUserController.java b/src/main/java/NextLevel/demo/admin/user/AdminUserController.java new file mode 100644 index 0000000..259643a --- /dev/null +++ b/src/main/java/NextLevel/demo/admin/user/AdminUserController.java @@ -0,0 +1,29 @@ +package NextLevel.demo.admin.user; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/admin") +public class AdminUserController { + + public ResponseEntity getUserList() { + return null; + } + + public ResponseEntity stopUser() { + return null; + } + + public ResponseEntity updateUser() { + return null; + } + + public ResponseEntity removeUser() { + return null; + } + +} diff --git a/src/main/java/NextLevel/demo/admin/user/AdminUserService.java b/src/main/java/NextLevel/demo/admin/user/AdminUserService.java new file mode 100644 index 0000000..4d3edca --- /dev/null +++ b/src/main/java/NextLevel/demo/admin/user/AdminUserService.java @@ -0,0 +1,37 @@ +package NextLevel.demo.admin.user; + +import NextLevel.demo.user.dto.user.response.ResponseUserInfoDetailDto; +import NextLevel.demo.user.repository.UserRepository; +import NextLevel.demo.user.service.UserService; +import NextLevel.demo.user.service.UserValidateService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class AdminUserService { + + private final UserValidateService userValidateService; + private final UserService userService; + private final UserRepository userRepository; + + public List getUserList(Pageable pageable) { + return userRepository.findAll(pageable).stream().map(ResponseUserInfoDetailDto::of).toList(); + } + + public void stopUser() { + // not yet + } + + public void updateUser() { + // userService.update + } + + public void removeUser() { + // userService. ; // delete 어디감? + } + +} diff --git a/src/main/java/NextLevel/demo/project/project/entity/ProjectEntity.java b/src/main/java/NextLevel/demo/project/project/entity/ProjectEntity.java index e8965e6..60469b3 100644 --- a/src/main/java/NextLevel/demo/project/project/entity/ProjectEntity.java +++ b/src/main/java/NextLevel/demo/project/project/entity/ProjectEntity.java @@ -87,6 +87,7 @@ public void setTags(List tags) { this.tags = tags; } public void setFundingData(ProjectEntity project) {this.freeFundings = project.getFreeFundings();this.options = project.getOptions();} + public void updateStatus(ProjectStatus status) { this.projectStatus = status; } @Builder public ProjectEntity(Long id, UserEntity user, String title, String content, diff --git a/src/main/java/NextLevel/demo/project/project/service/ProjectDeleteService.java b/src/main/java/NextLevel/demo/project/project/service/ProjectDeleteService.java new file mode 100644 index 0000000..25a56ba --- /dev/null +++ b/src/main/java/NextLevel/demo/project/project/service/ProjectDeleteService.java @@ -0,0 +1,44 @@ +package NextLevel.demo.project.project.service; + +import NextLevel.demo.exception.CustomException; +import NextLevel.demo.exception.ErrorCode; +import NextLevel.demo.funding.service.FundingRollbackService; +import NextLevel.demo.img.service.ImgTransaction; +import NextLevel.demo.project.project.entity.ProjectEntity; +import NextLevel.demo.project.project.repository.ProjectRepository; +import NextLevel.demo.project.story.service.ProjectStoryService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class ProjectDeleteService { + + private final ProjectRepository projectRepository; + private final ProjectStoryService projectStoryService; + private final ProjectValidateService projectValidateService; + private final FundingRollbackService fundingRollbackService; + + // 삭제 + @Transactional + @ImgTransaction + public void deleteProject(Long id, ArrayList imgPaths) { + ProjectEntity oldProject = projectValidateService.getProjectEntity(id); + + // 펀딩 금액이 남아있다면 모두 환불 처리하기 + fundingRollbackService.rollbackByProject(oldProject); + + // 다른 soft적 처리 필요한 부분 처리하기 + + // img 처리 + projectStoryService.updateProjectStory(oldProject, new ArrayList<>(), imgPaths); + + return; // 아직 구현하지 않음 + soft delete 처리 고민중 ..... + } + +} diff --git a/src/main/java/NextLevel/demo/project/project/service/ProjectService.java b/src/main/java/NextLevel/demo/project/project/service/ProjectService.java index ad809af..b6d4e89 100644 --- a/src/main/java/NextLevel/demo/project/project/service/ProjectService.java +++ b/src/main/java/NextLevel/demo/project/project/service/ProjectService.java @@ -47,7 +47,6 @@ public class ProjectService { private final FundingValidateService fundingValidateService; private final ProjectDslRepository projectDslRepository; - private final FundingRollbackService fundingRollbackService; private final ProjectValidateService projectValidateService; private final SelectSocialProfileService selectSocialProfileService; @@ -102,26 +101,6 @@ public void update(CreateProjectDto dto, ArrayList imgPaths) { projectRepository.save(dto.toProjectEntity(oldProject.getUser(), img)); // 값이 있는 것만 update 형식으로 수정 필요 } - // 삭제 - @Transactional - @ImgTransaction - public void deleteProject(Long id, ArrayList imgPaths) { - Optional oldProjectOptional = projectRepository.findById(id); - if(oldProjectOptional.isEmpty()) - throw new CustomException(ErrorCode.NOT_FOUND, "project"); - ProjectEntity oldProject = oldProjectOptional.get(); - - // 펀딩 금액이 남아있다면 모두 환불 처리하기 - fundingRollbackService.rollbackByProject(oldProject); - - // 다른 soft적 처리 필요한 부분 처리하기 - - // img 처리 - projectStoryService.updateProjectStory(oldProject, new ArrayList<>(), imgPaths); - - return; // 아직 구현하지 않음 + soft delete 처리 고민중 ..... - } - // get list public ResponseProjectListDto getAllProjects(RequestMainPageProjectListDto dto) { return projectDslRepository.selectProjectDsl(dto); diff --git a/src/main/java/NextLevel/demo/project/project/service/ProjectStatusService.java b/src/main/java/NextLevel/demo/project/project/service/ProjectStatusService.java new file mode 100644 index 0000000..c64abcc --- /dev/null +++ b/src/main/java/NextLevel/demo/project/project/service/ProjectStatusService.java @@ -0,0 +1,26 @@ +package NextLevel.demo.project.project.service; + +import NextLevel.demo.project.ProjectStatus; +import NextLevel.demo.project.project.entity.ProjectEntity; +import NextLevel.demo.project.project.repository.ProjectRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Slf4j +@RequiredArgsConstructor +public class ProjectStatusService { + + private final ProjectRepository projectRepository; + private final ProjectValidateService projectValidateService; + + @Transactional + public void updateProjectStatus(Long projectId, ProjectStatus status, String reason) { + ProjectEntity project = projectValidateService.getProjectEntity(projectId); + project.updateStatus(status); + log.info("project (id{}, title{}) status update : {}", project.getId(), project.getTitle(), reason); + } + +} From 6dc1c2fb7cb2549e855989e03f9435de5560d3f4 Mon Sep 17 00:00:00 2001 From: kwonhee1 Date: Sat, 11 Oct 2025 16:59:21 +0900 Subject: [PATCH 2/2] fix : catch one option two coupon --- .../NextLevel/demo/exception/ErrorCode.java | 1 + .../demo/funding/service/CouponService.java | 3 +++ .../demo/funding/service/FundingService.java | 23 ++++++++----------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/java/NextLevel/demo/exception/ErrorCode.java b/src/main/java/NextLevel/demo/exception/ErrorCode.java index 44bcd89..4f43fc1 100644 --- a/src/main/java/NextLevel/demo/exception/ErrorCode.java +++ b/src/main/java/NextLevel/demo/exception/ErrorCode.java @@ -36,6 +36,7 @@ public enum ErrorCode { // funding NOT_ENOUGH_POINT(HttpStatus.BAD_REQUEST, "05001","not enough point left:%s, need:%s"), ALREADY_USED_COUPON(HttpStatus.BAD_REQUEST, "05002","already used coupon"), + CAN_USE_COUPONS_AT_ONE_OPTION(HttpStatus.BAD_REQUEST, "05003", "can not user coupons at one option"), // option diff --git a/src/main/java/NextLevel/demo/funding/service/CouponService.java b/src/main/java/NextLevel/demo/funding/service/CouponService.java index d2c4181..604783f 100644 --- a/src/main/java/NextLevel/demo/funding/service/CouponService.java +++ b/src/main/java/NextLevel/demo/funding/service/CouponService.java @@ -43,6 +43,9 @@ public long useCoupon(long userId, long couponId, OptionFundingEntity optionFund if(coupon.getOptionFunding() != null) throw new CustomException(ErrorCode.ALREADY_USED_COUPON); + if(optionFunding.getCoupon() != null) + throw new CustomException(ErrorCode.CAN_USE_COUPONS_AT_ONE_OPTION); + price -= coupon.getPrice(); coupon.updateProjectFundingEntity(optionFunding); diff --git a/src/main/java/NextLevel/demo/funding/service/FundingService.java b/src/main/java/NextLevel/demo/funding/service/FundingService.java index 9275be7..7888931 100644 --- a/src/main/java/NextLevel/demo/funding/service/FundingService.java +++ b/src/main/java/NextLevel/demo/funding/service/FundingService.java @@ -69,35 +69,32 @@ public void cancelOptionFunding(RequestCancelFundingDto dto) { @Transactional public void optionFunding(@Valid RequestOptionFundingDto dto) { UserEntity user = userValidateService.getUserInfoWithAccessToken(dto.getUserId()); - OptionEntity option = optionValidateService.getOption(dto.getOptionId()); + OptionEntity option = optionValidateService.getOption(dto.getOptionId()); // option id가 null인 경우 - OptionFundingEntity entity = dto.toEntity(user, option); + OptionFundingEntity entity; + + Optional oldOptionFundingOpt = optionFundingRepository.findByOptionIdAndUserId(dto.getOptionId(), dto.getUserId()); + if(oldOptionFundingOpt.isPresent()) + entity = oldOptionFundingOpt.get(); + else + entity = dto.toEntity(user, option); // validate price <> option.price * count long totalPrice = option.getPrice() * dto.getCount(); if(dto.getCouponId() != null) - totalPrice = couponService.useCoupon(user.getId(), dto.getCouponId(), entity, totalPrice); + totalPrice = couponService.useCoupon(user.getId(), dto.getCouponId(), entity, totalPrice); // option update인 경우 이미 coupon을 사용했다면 rollback발생? if(totalPrice > user.getPoint()) throw new CustomException(ErrorCode.NOT_ENOUGH_POINT, String.valueOf(user.getPoint()), String.valueOf(totalPrice)); - Optional oldOptionFundingOpt = optionFundingRepository.findByOptionIdAndUserId(dto.getOptionId(), dto.getUserId()); - if(oldOptionFundingOpt.isPresent()) - oldOptionFundingOpt.get().updateCount(dto.getCount()); + entity.updateCount(dto.getCount()); else optionFundingRepository.save(entity); user.updatePoint(-totalPrice); } - // 분리 필요!! - // 이미 option1을 구매하면서 coupon1을 사용 -> 이후 option1을 추가 구매 (with other coupon) => error (coupon <> option 1대 1이여야 함!) - // 아니면 언제나 새로운 결제 정보를 db에 저장한다! (이게 좀 더 맞는듯, 갯수 col지우고) - private void updateOptionFunding() { - - } - @Transactional public void freeFunding(@Valid RequestFreeFundingDto dto) { UserEntity user = userValidateService.getUserInfoWithAccessToken(dto.getUserId());