Skip to content

Commit 4ffa593

Browse files
authored
feat : 쿠폰조회, 상세조회, 수정, 삭제 관리자 기능 구현
* feat:쿠폰목록조회(관리자) * feat:관리자계정추가 * feat:검증조건추가 * feat:쿠폰수정 * feat:쿠폰삭제 * refactor:페이지응답통일 * fix:checkstyle통일 * refactor:enum,공통메서드수정
1 parent c064152 commit 4ffa593

15 files changed

+611
-2
lines changed

src/main/java/com/threestar/trainus/domain/coupon/admin/controller/AdminCouponController.java

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,42 @@
22

33
import org.springframework.http.HttpStatus;
44
import org.springframework.http.ResponseEntity;
5+
import org.springframework.web.bind.annotation.DeleteMapping;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.PatchMapping;
8+
import org.springframework.web.bind.annotation.PathVariable;
59
import org.springframework.web.bind.annotation.PostMapping;
610
import org.springframework.web.bind.annotation.RequestBody;
711
import org.springframework.web.bind.annotation.RequestMapping;
12+
import org.springframework.web.bind.annotation.RequestParam;
813
import org.springframework.web.bind.annotation.RestController;
914

1015
import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateRequestDto;
1116
import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateResponseDto;
17+
import com.threestar.trainus.domain.coupon.admin.dto.CouponDeleteResponseDto;
18+
import com.threestar.trainus.domain.coupon.admin.dto.CouponDetailResponseDto;
19+
import com.threestar.trainus.domain.coupon.admin.dto.CouponListResponseDto;
20+
import com.threestar.trainus.domain.coupon.admin.dto.CouponListWrapperDto;
21+
import com.threestar.trainus.domain.coupon.admin.dto.CouponUpdateRequestDto;
22+
import com.threestar.trainus.domain.coupon.admin.dto.CouponUpdateResponseDto;
23+
import com.threestar.trainus.domain.coupon.admin.mapper.AdminCouponMapper;
1224
import com.threestar.trainus.domain.coupon.admin.service.AdminCouponService;
25+
import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
26+
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;
1327
import com.threestar.trainus.global.annotation.LoginUser;
1428
import com.threestar.trainus.global.unit.BaseResponse;
29+
import com.threestar.trainus.global.unit.PagedResponse;
1530

1631
import io.swagger.v3.oas.annotations.Operation;
1732
import io.swagger.v3.oas.annotations.tags.Tag;
1833
import jakarta.validation.Valid;
34+
import jakarta.validation.constraints.Max;
35+
import jakarta.validation.constraints.Min;
1936
import lombok.RequiredArgsConstructor;
2037

2138
@Tag(name = "관리자 쿠폰 API", description = "관리자 쿠폰 생성,수정 및 삭제 관련 API")
2239
@RestController
23-
@RequestMapping("/api/v1/coupons")
40+
@RequestMapping("/api/v1/admin/coupons")
2441
@RequiredArgsConstructor
2542
public class AdminCouponController {
2643

@@ -35,4 +52,54 @@ public ResponseEntity<BaseResponse<CouponCreateResponseDto>> createCoupon(
3552
CouponCreateResponseDto response = adminCouponService.createCoupon(request, loginUserId);
3653
return BaseResponse.ok("쿠폰 생성이 완료되었습니다.", response, HttpStatus.OK);
3754
}
55+
56+
@GetMapping
57+
@Operation(summary = "쿠폰 목록 조회", description = "관리자가 쿠폰 목록을 조회")
58+
public ResponseEntity<PagedResponse<CouponListWrapperDto>> getCoupons(
59+
@RequestParam(defaultValue = "1") @Min(value = 1, message = "페이지는 1 이상이어야 합니다.")
60+
@Max(value = 1000, message = "페이지는 1000 이하여야 합니다.") int page,
61+
@RequestParam(defaultValue = "5") @Min(value = 1, message = "limit는 1 이상이어야 합니다.")
62+
@Max(value = 100, message = "limit는 100 이하여야 합니다.") int limit,
63+
@RequestParam(required = false) CouponStatus status,
64+
@RequestParam(required = false) CouponCategory category,
65+
@LoginUser Long loginUserId
66+
) {
67+
CouponListResponseDto couponsInfo = adminCouponService.getCoupons(page, limit, status, category, loginUserId);
68+
69+
CouponListWrapperDto coupons = AdminCouponMapper.toCouponListWrapperDto(couponsInfo);
70+
71+
return PagedResponse.ok("쿠폰 목록 조회 완료.", coupons, couponsInfo.totalCount(), HttpStatus.OK);
72+
}
73+
74+
@GetMapping("/{couponId}")
75+
@Operation(summary = "쿠폰 상세 조회", description = "관리자가 특정 쿠폰의 상세 정보를 조회")
76+
public ResponseEntity<BaseResponse<CouponDetailResponseDto>> getCouponDetail(
77+
@PathVariable Long couponId,
78+
@LoginUser Long loginUserId
79+
) {
80+
CouponDetailResponseDto response = adminCouponService.getCouponDetail(couponId, loginUserId);
81+
return BaseResponse.ok("쿠폰 상세 조회 완료", response, HttpStatus.OK);
82+
}
83+
84+
@PatchMapping("/{couponId}")
85+
@Operation(summary = "쿠폰 수정", description = "관리자가 쿠폰 정보를 수정")
86+
public ResponseEntity<BaseResponse<CouponUpdateResponseDto>> updateCoupon(
87+
@PathVariable Long couponId,
88+
@Valid @RequestBody CouponUpdateRequestDto request,
89+
@LoginUser Long loginUserId
90+
) {
91+
CouponUpdateResponseDto response = adminCouponService.updateCoupon(couponId, request, loginUserId);
92+
return BaseResponse.ok("쿠폰 수정이 완료되었습니다.", response, HttpStatus.OK);
93+
}
94+
95+
@DeleteMapping("/{couponId}")
96+
@Operation(summary = "쿠폰 삭제", description = "관리자가 쿠폰을 삭제")
97+
public ResponseEntity<BaseResponse<CouponDeleteResponseDto>> deleteCoupon(
98+
@PathVariable Long couponId,
99+
@LoginUser Long loginUserId
100+
) {
101+
CouponDeleteResponseDto response = adminCouponService.deleteCoupon(couponId, loginUserId);
102+
return BaseResponse.ok("쿠폰 삭제가 완료되었습니다.", response, HttpStatus.OK);
103+
}
104+
38105
}

src/main/java/com/threestar/trainus/domain/coupon/admin/dto/CouponCreateRequestDto.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public record CouponCreateRequestDto(
2626
Integer minOrderPrice,
2727

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

3131
@Min(value = 1, message = "수량은 1개 이상이어야 합니다")
3232
Integer quantity,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.threestar.trainus.domain.coupon.admin.dto;
2+
3+
import java.time.LocalDateTime;
4+
5+
/**
6+
* 쿠폰 삭제 응답 DTO
7+
*/
8+
public record CouponDeleteResponseDto(
9+
Long couponId,
10+
String couponName,
11+
LocalDateTime deletedAt
12+
) {
13+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.threestar.trainus.domain.coupon.admin.dto;
2+
3+
import java.time.LocalDateTime;
4+
5+
import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
6+
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;
7+
8+
/**
9+
* 쿠폰 상세 조회 응답 DTO
10+
*/
11+
public record CouponDetailResponseDto(
12+
Long id,
13+
String couponName,
14+
LocalDateTime expirationDate,
15+
String discountPrice,
16+
Integer minOrderPrice,
17+
CouponStatus status,
18+
Integer quantity,
19+
CouponCategory couponCategory,
20+
LocalDateTime couponOpenAt,
21+
LocalDateTime couponDeadlineAt,
22+
LocalDateTime createdAt,
23+
LocalDateTime updatedAt,
24+
Integer issuedCount
25+
) {
26+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.threestar.trainus.domain.coupon.admin.dto;
2+
3+
import java.time.LocalDateTime;
4+
5+
import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
6+
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;
7+
8+
/**
9+
* 개별의 쿠폰 정보
10+
*/
11+
public record CouponListItemDto(
12+
Long couponId,
13+
String couponName,
14+
LocalDateTime expirationDate,
15+
String discountPrice,
16+
Integer minOrderPrice,
17+
LocalDateTime createdAt,
18+
LocalDateTime updatedAt,
19+
CouponStatus status,
20+
Integer quantity,
21+
CouponCategory category,
22+
LocalDateTime couponOpenAt,
23+
LocalDateTime couponDeadlineAt
24+
) {
25+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.threestar.trainus.domain.coupon.admin.dto;
2+
3+
import java.util.List;
4+
5+
public record CouponListResponseDto(
6+
Integer totalCount,
7+
List<CouponListItemDto> couponList
8+
) {
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.threestar.trainus.domain.coupon.admin.dto;
2+
3+
import java.util.List;
4+
5+
public record CouponListWrapperDto(
6+
List<CouponListItemDto> coupons
7+
) {
8+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.threestar.trainus.domain.coupon.admin.dto;
2+
3+
import java.time.LocalDateTime;
4+
5+
import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
6+
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;
7+
8+
import jakarta.validation.constraints.Min;
9+
import jakarta.validation.constraints.Size;
10+
11+
/**
12+
* 쿠폰 수정 요청 DTO
13+
* 일반쿠폰(NORMAL): 수량은 프론트에서 비활성화, 백엔드에서 자동으로 null 처리
14+
* 선착순쿠폰(OPEN_RUN): 수량 필수 입력
15+
*/
16+
public record CouponUpdateRequestDto(
17+
18+
@Size(max = 45, message = "쿠폰명은 45자 이하여야 합니다")
19+
String couponName,
20+
21+
CouponStatus status,
22+
23+
@Min(value = 1, message = "수량은 1개 이상이어야 합니다")
24+
Integer quantity,
25+
26+
CouponCategory category,
27+
28+
LocalDateTime couponOpenAt,
29+
30+
LocalDateTime couponDeadlineAt
31+
) {
32+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.threestar.trainus.domain.coupon.admin.dto;
2+
3+
import java.time.LocalDateTime;
4+
5+
import com.threestar.trainus.domain.coupon.user.entity.CouponCategory;
6+
import com.threestar.trainus.domain.coupon.user.entity.CouponStatus;
7+
8+
/**
9+
* 쿠폰 수정 응답 DTO
10+
*/
11+
public record CouponUpdateResponseDto(
12+
String couponName,
13+
CouponStatus status,
14+
Integer quantity,
15+
CouponCategory category,
16+
LocalDateTime couponOpenAt,
17+
LocalDateTime couponDeadlineAt,
18+
LocalDateTime updatedAt
19+
) {
20+
}

src/main/java/com/threestar/trainus/domain/coupon/admin/mapper/AdminCouponMapper.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
package com.threestar.trainus.domain.coupon.admin.mapper;
22

3+
import org.springframework.data.domain.Page;
4+
35
import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateRequestDto;
46
import com.threestar.trainus.domain.coupon.admin.dto.CouponCreateResponseDto;
7+
import com.threestar.trainus.domain.coupon.admin.dto.CouponDeleteResponseDto;
8+
import com.threestar.trainus.domain.coupon.admin.dto.CouponDetailResponseDto;
9+
import com.threestar.trainus.domain.coupon.admin.dto.CouponListItemDto;
10+
import com.threestar.trainus.domain.coupon.admin.dto.CouponListResponseDto;
11+
import com.threestar.trainus.domain.coupon.admin.dto.CouponListWrapperDto;
12+
import com.threestar.trainus.domain.coupon.admin.dto.CouponUpdateResponseDto;
513
import com.threestar.trainus.domain.coupon.user.entity.Coupon;
614

715
public class AdminCouponMapper {
@@ -31,4 +39,72 @@ public static CouponCreateResponseDto toCreateResponseDto(Coupon coupon) {
3139
coupon.getCreatedAt()
3240
);
3341
}
42+
43+
public static CouponListItemDto toCouponListItemDto(Coupon coupon) {
44+
return new CouponListItemDto(
45+
coupon.getId(),
46+
coupon.getName(),
47+
coupon.getExpirationDate(),
48+
coupon.getDiscountPrice(),
49+
coupon.getMinOrderPrice(),
50+
coupon.getCreatedAt(),
51+
coupon.getUpdatedAt(),
52+
coupon.getStatus(),
53+
coupon.getQuantity(),
54+
coupon.getCategory(),
55+
coupon.getOpenAt(),
56+
coupon.getCloseAt()
57+
);
58+
}
59+
60+
public static CouponListResponseDto toCouponListResponseDto(Page<Coupon> couponPage) {
61+
return new CouponListResponseDto(
62+
(int)couponPage.getTotalElements(),
63+
couponPage.getContent().stream()
64+
.map(AdminCouponMapper::toCouponListItemDto)
65+
.toList()
66+
);
67+
}
68+
69+
public static CouponDetailResponseDto toCouponDetailResponseDto(Coupon coupon, Integer issuedCount) {
70+
return new CouponDetailResponseDto(
71+
coupon.getId(),
72+
coupon.getName(),
73+
coupon.getExpirationDate(),
74+
coupon.getDiscountPrice(),
75+
coupon.getMinOrderPrice(),
76+
coupon.getStatus(),
77+
coupon.getQuantity(),
78+
coupon.getCategory(),
79+
coupon.getOpenAt(),
80+
coupon.getCloseAt(),
81+
coupon.getCreatedAt(),
82+
coupon.getUpdatedAt(),
83+
issuedCount
84+
);
85+
}
86+
87+
public static CouponUpdateResponseDto toCouponUpdateResponseDto(Coupon coupon) {
88+
return new CouponUpdateResponseDto(
89+
coupon.getName(),
90+
coupon.getStatus(),
91+
coupon.getQuantity(),
92+
coupon.getCategory(),
93+
coupon.getOpenAt(),
94+
coupon.getCloseAt(),
95+
coupon.getUpdatedAt()
96+
);
97+
}
98+
99+
public static CouponDeleteResponseDto toCouponDeleteResponseDto(Coupon coupon) {
100+
return new CouponDeleteResponseDto(
101+
coupon.getId(),
102+
coupon.getName(),
103+
coupon.getDeletedAt()
104+
);
105+
}
106+
107+
public static CouponListWrapperDto toCouponListWrapperDto(CouponListResponseDto couponsInfo) {
108+
return new CouponListWrapperDto(couponsInfo.couponList());
109+
}
34110
}

0 commit comments

Comments
 (0)