-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 쿠폰 발행 기능 구현 및 테스트 #57
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
06070e2
feat: 쿠폰 엔티티 설계
hongdosan ffea54a
test: Coupon Entity 테스트
hongdosan 817abd1
refactor: 초기값 0에서 1로 지정
hongdosan a22f382
feat: 쿠폰 종류에 대한 조회 처리 구현 및 테스트
hongdosan 13c8ccc
refactor: 쿠폰 컬럼으로 관리자 아이디 추가
hongdosan 704777f
feat: 관리자의 쿠폰 생성 기능 구현
hongdosan d40b614
test: 쿠폰 발행 기능 테스트
hongdosan 923b2ec
test: 쿠폰 엔티티 테스트 추가
hongdosan f0dd697
style: test 메서드 변경
hongdosan 4aa35bd
fix: CheckStyle 수정
hongdosan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
== 쿠폰(Coupon) | ||
|
||
쿠폰에 대해 생성/삭제/조회/발급/사용 기능을 제공합니다. | ||
|
||
=== 쿠폰 생성 | ||
|
||
관리자가 쿠폰을 생성합니다. | ||
|
||
[discrete] | ||
==== 요청 | ||
|
||
include::{snippets}/coupons/http-request.adoc[] | ||
|
||
[discrete] | ||
==== 응답 | ||
|
||
include::{snippets}/coupons/http-response.adoc[] | ||
|
||
=== 쿠폰 삭제 (진행 중) | ||
|
||
관리자가 쿠폰을 삭제합니다. | ||
|
||
=== 쿠폰 조회 (진행 중) | ||
|
||
관리자 혹은 사용자가 쿠폰들을 조회합니다. | ||
|
||
사용자가 자신의 보관함에 있는 쿠폰들을 조회합니다. | ||
|
||
=== 쿠폰 발급 (진행 중) | ||
|
||
사용자가 발급 가능한 쿠폰을 선착순으로 발급 받습니다. | ||
|
||
=== 쿠폰 사용 (진행 중) | ||
|
||
사용자가 자신의 보관함에 있는 쿠폰들을 사용합니다. |
45 changes: 45 additions & 0 deletions
45
src/main/java/com/moabam/api/application/CouponService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.moabam.api.application; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import com.moabam.api.domain.entity.Coupon; | ||
import com.moabam.api.domain.repository.CouponRepository; | ||
import com.moabam.api.dto.CouponMapper; | ||
import com.moabam.api.dto.CreateCouponRequest; | ||
import com.moabam.global.error.exception.BadRequestException; | ||
import com.moabam.global.error.exception.ConflictException; | ||
import com.moabam.global.error.model.ErrorMessage; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
public class CouponService { | ||
|
||
private final CouponRepository couponRepository; | ||
|
||
@Transactional | ||
public void createCoupon(Long adminId, CreateCouponRequest request) { | ||
validateConflictCouponName(request.name()); | ||
validateCouponPeriod(request.startAt(), request.endAt()); | ||
|
||
Coupon coupon = CouponMapper.toEntity(adminId, request); | ||
couponRepository.save(coupon); | ||
} | ||
|
||
private void validateConflictCouponName(String name) { | ||
if (couponRepository.existsByName(name)) { | ||
throw new ConflictException(ErrorMessage.CONFLICT_COUPON_NAME); | ||
} | ||
} | ||
|
||
private void validateCouponPeriod(LocalDateTime startAt, LocalDateTime endAt) { | ||
if (startAt.isAfter(endAt)) { | ||
throw new BadRequestException(ErrorMessage.INVALID_COUPON_PERIOD); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package com.moabam.api.domain.entity; | ||
|
||
import static com.moabam.global.error.model.ErrorMessage.*; | ||
import static java.util.Objects.*; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
import org.hibernate.annotations.ColumnDefault; | ||
|
||
import com.moabam.api.domain.entity.enums.CouponType; | ||
import com.moabam.global.common.entity.BaseTimeEntity; | ||
import com.moabam.global.error.exception.BadRequestException; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.EnumType; | ||
import jakarta.persistence.Enumerated; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Getter | ||
@Table(name = "coupon") | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class Coupon extends BaseTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "id") | ||
private Long id; | ||
|
||
@Column(name = "name", nullable = false, unique = true, length = 20) | ||
private String name; | ||
|
||
@ColumnDefault("1") | ||
@Column(name = "point", nullable = false) | ||
private int point; | ||
|
||
@Column(name = "description", length = 50) | ||
private String description; | ||
|
||
@Enumerated(value = EnumType.STRING) | ||
@Column(name = "type", nullable = false) | ||
private CouponType type; | ||
|
||
@ColumnDefault("1") | ||
@Column(name = "stock", nullable = false) | ||
private int stock; | ||
|
||
@Column(name = "start_at", nullable = false) | ||
private LocalDateTime startAt; | ||
|
||
@Column(name = "end_at", nullable = false) | ||
private LocalDateTime endAt; | ||
|
||
@Column(name = "admin_id", updatable = false, nullable = false) | ||
private Long adminId; | ||
|
||
@Builder | ||
private Coupon(String name, int point, String description, CouponType type, int stock, LocalDateTime startAt, | ||
LocalDateTime endAt, Long adminId) { | ||
this.name = requireNonNull(name); | ||
this.point = validatePoint(point); | ||
this.description = description; | ||
this.type = requireNonNull(type); | ||
this.stock = validateStock(stock); | ||
this.startAt = requireNonNull(startAt); | ||
this.endAt = requireNonNull(endAt); | ||
this.adminId = requireNonNull(adminId); | ||
} | ||
|
||
private int validatePoint(int point) { | ||
if (point < 1) { | ||
throw new BadRequestException(INVALID_COUPON_POINT); | ||
} | ||
|
||
return point; | ||
} | ||
|
||
private int validateStock(int stock) { | ||
if (stock < 1) { | ||
throw new BadRequestException(INVALID_COUPON_STOCK); | ||
} | ||
|
||
return stock; | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
src/main/java/com/moabam/api/domain/entity/enums/CouponType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.moabam.api.domain.entity.enums; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
|
||
import com.moabam.global.error.exception.NotFoundException; | ||
import com.moabam.global.error.model.ErrorMessage; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) | ||
public enum CouponType { | ||
|
||
MORNING_COUPON("아침"), | ||
NIGHT_COUPON("저녁"), | ||
GOLDEN_COUPON("황금"), | ||
DISCOUNT_COUPON("할인"); | ||
|
||
private final String typeName; | ||
private static final Map<String, CouponType> COUPON_TYPE_MAP; | ||
|
||
static { | ||
COUPON_TYPE_MAP = Collections.unmodifiableMap(Arrays.stream(values()) | ||
.collect(Collectors.toMap(CouponType::getTypeName, Function.identity()))); | ||
} | ||
|
||
public static CouponType from(String typeName) { | ||
return Optional.ofNullable(COUPON_TYPE_MAP.get(typeName)) | ||
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_TYPE)); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/moabam/api/domain/repository/CouponRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.moabam.api.domain.repository; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import com.moabam.api.domain.entity.Coupon; | ||
|
||
public interface CouponRepository extends JpaRepository<Coupon, Long> { | ||
|
||
boolean existsByName(String name); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.moabam.api.dto; | ||
|
||
import com.moabam.api.domain.entity.Coupon; | ||
import com.moabam.api.domain.entity.enums.CouponType; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.NoArgsConstructor; | ||
|
||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
public final class CouponMapper { | ||
|
||
public static Coupon toEntity(Long adminId, CreateCouponRequest request) { | ||
return Coupon.builder() | ||
.name(request.name()) | ||
.description(request.description()) | ||
.type(CouponType.from(request.type())) | ||
.point(request.point()) | ||
.stock(request.stock()) | ||
.startAt(request.startAt()) | ||
.endAt(request.endAt()) | ||
.adminId(adminId) | ||
.build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.moabam.api.dto; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
import org.hibernate.validator.constraints.Length; | ||
|
||
import com.fasterxml.jackson.annotation.JsonFormat; | ||
|
||
import jakarta.validation.constraints.Min; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.NotNull; | ||
import lombok.Builder; | ||
|
||
@Builder | ||
public record CreateCouponRequest( | ||
@NotBlank(message = "쿠폰명이 입력되지 않았거나 20자를 넘었습니다.") @Length(max = 20) String name, | ||
@Length(max = 50, message = "쿠폰 간단 소개는 최대 50자까지 가능합니다.") String description, | ||
@NotBlank(message = "쿠폰 종류를 입력해주세요.") String type, | ||
@Min(value = 1, message = "벌레 수 혹은 할인 금액은 1 이상이어야 합니다.") int point, | ||
@Min(value = 1, message = "쿠폰 재고는 1 이상이어야 합니다.") int stock, | ||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm") | ||
@NotNull(message = "쿠폰 발급 시작 시각을 입력해주세요.") LocalDateTime startAt, | ||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm") | ||
@NotNull(message = "쿠폰 발급 종료 시각을 입력해주세요.") LocalDateTime endAt | ||
) { | ||
|
||
} |
27 changes: 27 additions & 0 deletions
27
src/main/java/com/moabam/api/presentation/CouponController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.moabam.api.presentation; | ||
|
||
import org.springframework.http.HttpStatus; | ||
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.ResponseStatus; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import com.moabam.api.application.CouponService; | ||
import com.moabam.api.dto.CreateCouponRequest; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/admins/coupons") | ||
public class CouponController { | ||
|
||
private final CouponService couponService; | ||
|
||
@PostMapping | ||
@ResponseStatus(HttpStatus.OK) | ||
public void createCoupon(@RequestBody CreateCouponRequest request) { | ||
couponService.createCoupon(1L, request); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: 아침 저녁 황금과 할인의 차이가 뭔가요?
할인이 지난번 얘기가 나왔던 결제 시 할인인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
맞습니다! 할인은 결제 시 할인 입니다!