Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,42 @@

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateRequestDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponDeleteResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponDetailResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponListResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponListWrapperDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponUpdateRequestDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponUpdateResponseDto;
import com.threestar.trainus.domain.coupon.admin.mapper.AdminCouponMapper;
import com.threestar.trainus.domain.coupon.admin.service.AdminCouponService;
import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;
import com.threestar.trainus.global.annotation.LoginUser;
import com.threestar.trainus.global.unit.BaseResponse;
import com.threestar.trainus.global.unit.PagedResponse;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;

@Tag(name = "관리자 쿠폰 API", description = "관리자 쿠폰 생성,수정 및 삭제 관련 API")
@RestController
@RequestMapping("/api/v1/coupons")
@RequestMapping("/api/v1/admin/coupons")
@RequiredArgsConstructor
public class AdminCouponController {

Expand All @@ -35,4 +52,54 @@ public ResponseEntity<BaseResponse<CouponCreateResponseDto>> createCoupon(
CouponCreateResponseDto response = adminCouponService.createCoupon(request, loginUserId);
return BaseResponse.ok("쿠폰 생성이 완료되었습니다.", response, HttpStatus.OK);
}

@GetMapping
@Operation(summary = "쿠폰 목록 조회", description = "관리자가 쿠폰 목록을 조회")
public ResponseEntity<PagedResponse<CouponListWrapperDto>> getCoupons(
@RequestParam(defaultValue = "1") @Min(value = 1, message = "페이지는 1 이상이어야 합니다.")
@Max(value = 1000, message = "페이지는 1000 이하여야 합니다.") int page,
@RequestParam(defaultValue = "5") @Min(value = 1, message = "limit는 1 이상이어야 합니다.")
@Max(value = 100, message = "limit는 100 이하여야 합니다.") int limit,
Comment on lines +59 to +62
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 공통사용되는 부분이 많아서 제가 global dto로 빼서 리팩토링하겠습니다

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵!!!

@RequestParam(required = false) CouponStatus status,
@RequestParam(required = false) CouponCategory category,
@LoginUser Long loginUserId
) {
CouponListResponseDto couponsInfo = adminCouponService.getCoupons(page, limit, status, category, loginUserId);

CouponListWrapperDto coupons = AdminCouponMapper.toCouponListWrapperDto(couponsInfo);

return PagedResponse.ok("쿠폰 목록 조회 완료.", coupons, couponsInfo.totalCount(), HttpStatus.OK);
}

@GetMapping("/{couponId}")
@Operation(summary = "쿠폰 상세 조회", description = "관리자가 특정 쿠폰의 상세 정보를 조회")
public ResponseEntity<BaseResponse<CouponDetailResponseDto>> getCouponDetail(
@PathVariable Long couponId,
@LoginUser Long loginUserId
) {
CouponDetailResponseDto response = adminCouponService.getCouponDetail(couponId, loginUserId);
return BaseResponse.ok("쿠폰 상세 조회 완료", response, HttpStatus.OK);
}

@PatchMapping("/{couponId}")
@Operation(summary = "쿠폰 수정", description = "관리자가 쿠폰 정보를 수정")
public ResponseEntity<BaseResponse<CouponUpdateResponseDto>> updateCoupon(
@PathVariable Long couponId,
@Valid @RequestBody CouponUpdateRequestDto request,
@LoginUser Long loginUserId
) {
CouponUpdateResponseDto response = adminCouponService.updateCoupon(couponId, request, loginUserId);
return BaseResponse.ok("쿠폰 수정이 완료되었습니다.", response, HttpStatus.OK);
}

@DeleteMapping("/{couponId}")
@Operation(summary = "쿠폰 삭제", description = "관리자가 쿠폰을 삭제")
public ResponseEntity<BaseResponse<CouponDeleteResponseDto>> deleteCoupon(
@PathVariable Long couponId,
@LoginUser Long loginUserId
) {
CouponDeleteResponseDto response = adminCouponService.deleteCoupon(couponId, loginUserId);
return BaseResponse.ok("쿠폰 삭제가 완료되었습니다.", response, HttpStatus.OK);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public record CouponCreateRequestDto(
Integer minOrderPrice,

@NotNull(message = "쿠폰 상태는 필수입니다")
CouponStatus status,
CouponStatus status, //TODO : 일단은 내가 상태설정하게 두고, 리팩토링때 스케줄러로 처리하도록 변경
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스케줄러는 어떤 로직을 처리하기 위해 도입되는건가용 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inactive상태일때, 쿠폰시작시간이 되면 자동으로 active상태로 변환시켜주기위해서 사용할 것 같습니다.


@Min(value = 1, message = "수량은 1개 이상이어야 합니다")
Integer quantity,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.threestar.trainus.domain.coupon.admin.dto;

import java.time.LocalDateTime;

/**
* 쿠폰 삭제 응답 DTO
*/
public record CouponDeleteResponseDto(
Long couponId,
String couponName,
LocalDateTime deletedAt
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.threestar.trainus.domain.coupon.admin.dto;

import java.time.LocalDateTime;

import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;

/**
* 쿠폰 상세 조회 응답 DTO
*/
public record CouponDetailResponseDto(
Long id,
String couponName,
LocalDateTime expirationDate,
String discountPrice,
Integer minOrderPrice,
CouponStatus status,
Integer quantity,
CouponCategory couponCategory,
LocalDateTime couponOpenAt,
LocalDateTime couponDeadlineAt,
LocalDateTime createdAt,
LocalDateTime updatedAt,
Integer issuedCount
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.threestar.trainus.domain.coupon.admin.dto;

import java.time.LocalDateTime;

import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;

/**
* 개별의 쿠폰 정보
*/
public record CouponListItemDto(
Long couponId,
String couponName,
LocalDateTime expirationDate,
String discountPrice,
Integer minOrderPrice,
LocalDateTime createdAt,
LocalDateTime updatedAt,
CouponStatus status,
Integer quantity,
CouponCategory category,
LocalDateTime couponOpenAt,
LocalDateTime couponDeadlineAt
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.threestar.trainus.domain.coupon.admin.dto;

import java.util.List;

public record CouponListResponseDto(
Integer totalCount,
List<CouponListItemDto> couponList
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.threestar.trainus.domain.coupon.admin.dto;

import java.util.List;

public record CouponListWrapperDto(
List<CouponListItemDto> coupons
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.threestar.trainus.domain.coupon.admin.dto;

import java.time.LocalDateTime;

import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Size;

/**
* 쿠폰 수정 요청 DTO
* 일반쿠폰(NORMAL): 수량은 프론트에서 비활성화, 백엔드에서 자동으로 null 처리
* 선착순쿠폰(OPEN_RUN): 수량 필수 입력
*/
public record CouponUpdateRequestDto(

@Size(max = 45, message = "쿠폰명은 45자 이하여야 합니다")
String couponName,

CouponStatus status,

@Min(value = 1, message = "수량은 1개 이상이어야 합니다")
Integer quantity,

CouponCategory category,

LocalDateTime couponOpenAt,

LocalDateTime couponDeadlineAt
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.threestar.trainus.domain.coupon.admin.dto;

import java.time.LocalDateTime;

import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;

/**
* 쿠폰 수정 응답 DTO
*/
public record CouponUpdateResponseDto(
String couponName,
CouponStatus status,
Integer quantity,
CouponCategory category,
LocalDateTime couponOpenAt,
LocalDateTime couponDeadlineAt,
LocalDateTime updatedAt
) {
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package com.threestar.trainus.domain.coupon.admin.mapper;

import org.springframework.data.domain.Page;

import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateRequestDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponDeleteResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponDetailResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponListItemDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponListResponseDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponListWrapperDto;
import com.threestar.trainus.domain.coupon.admin.dto.CouponUpdateResponseDto;
import com.threestar.trainus.domain.coupon.user.entity.Coupon;

public class AdminCouponMapper {
Expand Down Expand Up @@ -31,4 +39,72 @@ public static CouponCreateResponseDto toCreateResponseDto(Coupon coupon) {
coupon.getCreatedAt()
);
}

public static CouponListItemDto toCouponListItemDto(Coupon coupon) {
return new CouponListItemDto(
coupon.getId(),
coupon.getName(),
coupon.getExpirationDate(),
coupon.getDiscountPrice(),
coupon.getMinOrderPrice(),
coupon.getCreatedAt(),
coupon.getUpdatedAt(),
coupon.getStatus(),
coupon.getQuantity(),
coupon.getCategory(),
coupon.getOpenAt(),
coupon.getCloseAt()
);
}

public static CouponListResponseDto toCouponListResponseDto(Page<Coupon> couponPage) {
return new CouponListResponseDto(
(int)couponPage.getTotalElements(),
couponPage.getContent().stream()
.map(AdminCouponMapper::toCouponListItemDto)
.toList()
);
}

public static CouponDetailResponseDto toCouponDetailResponseDto(Coupon coupon, Integer issuedCount) {
return new CouponDetailResponseDto(
coupon.getId(),
coupon.getName(),
coupon.getExpirationDate(),
coupon.getDiscountPrice(),
coupon.getMinOrderPrice(),
coupon.getStatus(),
coupon.getQuantity(),
coupon.getCategory(),
coupon.getOpenAt(),
coupon.getCloseAt(),
coupon.getCreatedAt(),
coupon.getUpdatedAt(),
issuedCount
);
}

public static CouponUpdateResponseDto toCouponUpdateResponseDto(Coupon coupon) {
return new CouponUpdateResponseDto(
coupon.getName(),
coupon.getStatus(),
coupon.getQuantity(),
coupon.getCategory(),
coupon.getOpenAt(),
coupon.getCloseAt(),
coupon.getUpdatedAt()
);
}

public static CouponDeleteResponseDto toCouponDeleteResponseDto(Coupon coupon) {
return new CouponDeleteResponseDto(
coupon.getId(),
coupon.getName(),
coupon.getDeletedAt()
);
}

public static CouponListWrapperDto toCouponListWrapperDto(CouponListResponseDto couponsInfo) {
return new CouponListWrapperDto(couponsInfo.couponList());
}
}
Loading