diff --git a/src/docs/asciidoc/coupon.adoc b/src/docs/asciidoc/coupon.adoc index 4f424964..222be81b 100644 --- a/src/docs/asciidoc/coupon.adoc +++ b/src/docs/asciidoc/coupon.adoc @@ -96,6 +96,17 @@ include::{snippets}/my-coupons/couponId/http-response.adoc[] --- -=== 쿠폰 사용 (진행 중) +=== 쿠폰을 사용 사용자가 자신의 보관함에 있는 쿠폰들을 사용합니다. + +==== 요청 + +include::{snippets}/my-coupons/couponWalletId/http-request.adoc[] + +[discrete] +==== 응답 + +include::{snippets}/my-coupons/couponWalletId/http-response.adoc[] + +--- diff --git a/src/main/java/com/moabam/api/application/bug/BugService.java b/src/main/java/com/moabam/api/application/bug/BugService.java index d35e7549..297df42b 100644 --- a/src/main/java/com/moabam/api/application/bug/BugService.java +++ b/src/main/java/com/moabam/api/application/bug/BugService.java @@ -16,7 +16,7 @@ import com.moabam.api.domain.bug.Bug; import com.moabam.api.domain.bug.repository.BugHistoryRepository; import com.moabam.api.domain.bug.repository.BugHistorySearchRepository; -import com.moabam.api.domain.coupon.Coupon; +import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.api.domain.payment.Payment; import com.moabam.api.domain.payment.repository.PaymentRepository; import com.moabam.api.domain.product.Product; @@ -67,8 +67,8 @@ public PurchaseProductResponse purchaseBugProduct(Long memberId, Long productId, Payment payment = PaymentMapper.toPayment(memberId, product); if (!isNull(request.couponWalletId())) { - Coupon coupon = couponService.getByWalletIdAndMemberId(request.couponWalletId(), memberId); - payment.applyCoupon(coupon, request.couponWalletId()); + CouponWallet couponWallet = couponService.getWalletByIdAndMemberId(request.couponWalletId(), memberId); + payment.applyCoupon(couponWallet); } paymentRepository.save(payment); diff --git a/src/main/java/com/moabam/api/application/coupon/CouponService.java b/src/main/java/com/moabam/api/application/coupon/CouponService.java index 598e0c27..1d36be55 100644 --- a/src/main/java/com/moabam/api/application/coupon/CouponService.java +++ b/src/main/java/com/moabam/api/application/coupon/CouponService.java @@ -6,11 +6,15 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.moabam.api.application.member.MemberService; +import com.moabam.api.domain.bug.BugType; import com.moabam.api.domain.coupon.Coupon; import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.api.domain.coupon.repository.CouponRepository; import com.moabam.api.domain.coupon.repository.CouponSearchRepository; +import com.moabam.api.domain.coupon.repository.CouponWalletRepository; import com.moabam.api.domain.coupon.repository.CouponWalletSearchRepository; +import com.moabam.api.domain.member.Member; import com.moabam.api.domain.member.Role; import com.moabam.api.dto.coupon.CouponResponse; import com.moabam.api.dto.coupon.CouponStatusRequest; @@ -31,9 +35,11 @@ public class CouponService { private final ClockHolder clockHolder; + private final MemberService memberService; private final CouponManageService couponManageService; private final CouponRepository couponRepository; private final CouponSearchRepository couponSearchRepository; + private final CouponWalletRepository couponWalletRepository; private final CouponWalletSearchRepository couponWalletSearchRepository; @Transactional @@ -47,6 +53,30 @@ public void create(AuthMember admin, CreateCouponRequest request) { couponRepository.save(coupon); } + @Transactional + public void use(Long memberId, Long couponWalletId) { + CouponWallet couponWallet = getWalletByIdAndMemberId(couponWalletId, memberId); + Coupon coupon = couponWallet.getCoupon(); + BugType bugType = coupon.getType().getBugType(); + + Member member = memberService.findMember(memberId); + member.getBug().increase(bugType, coupon.getPoint()); + + couponWalletRepository.delete(couponWallet); + } + + @Transactional + public void discount(Long memberId, Long couponWalletId) { + CouponWallet couponWallet = getWalletByIdAndMemberId(couponWalletId, memberId); + Coupon coupon = couponWallet.getCoupon(); + + if (!coupon.getType().isDiscount()) { + throw new BadRequestException(ErrorMessage.INVALID_BUG_COUPON); + } + + couponWalletRepository.delete(couponWallet); + } + @Transactional public void delete(AuthMember admin, Long couponId) { validateAdminRole(admin); @@ -56,12 +86,6 @@ public void delete(AuthMember admin, Long couponId) { couponManageService.deleteCouponManage(coupon.getName()); } - @Transactional - public void use(Long memberId, Long couponWalletId) { - Coupon coupon = getByWalletIdAndMemberId(couponWalletId, memberId); - couponRepository.delete(coupon); - } - public CouponResponse getById(Long couponId) { Coupon coupon = couponRepository.findById(couponId) .orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON)); @@ -83,10 +107,9 @@ public List getWallet(Long couponId, AuthMember authMember) { return CouponMapper.toMyResponses(couponWallets); } - public Coupon getByWalletIdAndMemberId(Long couponWalletId, Long memberId) { + public CouponWallet getWalletByIdAndMemberId(Long couponWalletId, Long memberId) { return couponWalletSearchRepository.findByIdAndMemberId(couponWalletId, memberId) - .orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_WALLET)) - .getCoupon(); + .orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_WALLET)); } private void validatePeriod(LocalDate startAt, LocalDate openAt) { diff --git a/src/main/java/com/moabam/api/application/payment/PaymentService.java b/src/main/java/com/moabam/api/application/payment/PaymentService.java index 0055813b..b17c3e8d 100644 --- a/src/main/java/com/moabam/api/application/payment/PaymentService.java +++ b/src/main/java/com/moabam/api/application/payment/PaymentService.java @@ -50,7 +50,7 @@ public void confirm(Long memberId, ConfirmPaymentRequest request) { payment.confirm(response.paymentKey(), response.approvedAt()); if (payment.isCouponApplied()) { - couponService.use(memberId, payment.getCouponWalletId()); + couponService.discount(memberId, payment.getCouponWalletId()); } bugService.charge(memberId, payment.getProduct()); } catch (MoabamException exception) { diff --git a/src/main/java/com/moabam/api/domain/coupon/CouponType.java b/src/main/java/com/moabam/api/domain/coupon/CouponType.java index 722d4e8a..ddcfe57a 100644 --- a/src/main/java/com/moabam/api/domain/coupon/CouponType.java +++ b/src/main/java/com/moabam/api/domain/coupon/CouponType.java @@ -7,6 +7,8 @@ import java.util.function.Function; import java.util.stream.Collectors; +import com.moabam.api.domain.bug.BugType; +import com.moabam.global.error.exception.BadRequestException; import com.moabam.global.error.exception.NotFoundException; import com.moabam.global.error.model.ErrorMessage; @@ -18,10 +20,10 @@ @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public enum CouponType { - MORNING_COUPON("아침"), - NIGHT_COUPON("저녁"), - GOLDEN_COUPON("황금"), - DISCOUNT_COUPON("할인"); + MORNING("아침"), + NIGHT("저녁"), + GOLDEN("황금"), + DISCOUNT("할인"); private final String name; private static final Map COUPON_TYPE_MAP; @@ -35,4 +37,24 @@ public static CouponType from(String name) { return Optional.ofNullable(COUPON_TYPE_MAP.get(name)) .orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON_TYPE)); } + + public boolean isDiscount() { + return this == CouponType.DISCOUNT; + } + + public BugType getBugType() { + if (this == CouponType.MORNING) { + return BugType.MORNING; + } + + if (this == CouponType.NIGHT) { + return BugType.NIGHT; + } + + if (this == CouponType.GOLDEN) { + return BugType.GOLDEN; + } + + throw new BadRequestException(ErrorMessage.INVALID_DISCOUNT_COUPON); + } } diff --git a/src/main/java/com/moabam/api/domain/payment/Payment.java b/src/main/java/com/moabam/api/domain/payment/Payment.java index 9c1f4dea..f2056499 100644 --- a/src/main/java/com/moabam/api/domain/payment/Payment.java +++ b/src/main/java/com/moabam/api/domain/payment/Payment.java @@ -8,7 +8,7 @@ import org.springframework.data.annotation.CreatedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import com.moabam.api.domain.coupon.Coupon; +import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.api.domain.product.Product; import com.moabam.global.error.exception.BadRequestException; @@ -122,10 +122,10 @@ public boolean isCouponApplied() { return !isNull(this.couponWalletId); } - public void applyCoupon(Coupon coupon, Long couponWalletId) { - this.couponWalletId = couponWalletId; - this.discountAmount = coupon.getPoint(); - this.totalAmount = Math.max(MIN_AMOUNT, this.totalAmount - coupon.getPoint()); + public void applyCoupon(CouponWallet couponWallet) { + this.couponWalletId = couponWallet.getId(); + this.discountAmount = couponWallet.getCoupon().getPoint(); + this.totalAmount = Math.max(MIN_AMOUNT, this.totalAmount - this.discountAmount); } public void request(String orderId) { diff --git a/src/main/java/com/moabam/api/presentation/CouponController.java b/src/main/java/com/moabam/api/presentation/CouponController.java index e61b5c6b..8de012fa 100644 --- a/src/main/java/com/moabam/api/presentation/CouponController.java +++ b/src/main/java/com/moabam/api/presentation/CouponController.java @@ -33,13 +33,13 @@ public class CouponController { @PostMapping("/admins/coupons") @ResponseStatus(HttpStatus.CREATED) - public void createCoupon(@Auth AuthMember admin, @Valid @RequestBody CreateCouponRequest request) { + public void create(@Auth AuthMember admin, @Valid @RequestBody CreateCouponRequest request) { couponService.create(admin, request); } @DeleteMapping("/admins/coupons/{couponId}") @ResponseStatus(HttpStatus.OK) - public void deleteCoupon(@Auth AuthMember admin, @PathVariable("couponId") Long couponId) { + public void delete(@Auth AuthMember admin, @PathVariable("couponId") Long couponId) { couponService.delete(admin, couponId); } @@ -56,13 +56,21 @@ public List getAllByStatus(@Valid @RequestBody CouponStatusReque } @PostMapping("/coupons") + @ResponseStatus(HttpStatus.OK) public void registerQueue(@Auth AuthMember authMember, @RequestParam("couponName") String couponName) { couponManageService.register(authMember, couponName); } @GetMapping({"/my-coupons", "/my-coupons/{couponId}"}) + @ResponseStatus(HttpStatus.OK) public List getWallet(@Auth AuthMember authMember, @PathVariable(value = "couponId", required = false) Long couponId) { return couponService.getWallet(couponId, authMember); } + + @PostMapping("/my-coupons/{couponWalletId}") + @ResponseStatus(HttpStatus.OK) + public void use(@Auth AuthMember authMember, @PathVariable("couponWalletId") Long couponWalletId) { + couponService.use(authMember.id(), couponWalletId); + } } diff --git a/src/main/java/com/moabam/global/error/model/ErrorMessage.java b/src/main/java/com/moabam/global/error/model/ErrorMessage.java index 078d7fba..4d06627d 100644 --- a/src/main/java/com/moabam/global/error/model/ErrorMessage.java +++ b/src/main/java/com/moabam/global/error/model/ErrorMessage.java @@ -73,6 +73,8 @@ public enum ErrorMessage { INVALID_COUPON_START_AT_PERIOD("쿠폰 발급 시작 날짜는 현재 날짜보다 이전이거나 같을 수 없습니다."), INVALID_COUPON_OPEN_AT_PERIOD("쿠폰 정보 오픈 날짜는 시작 날짜보다 이전이여야 합니다."), INVALID_COUPON_PERIOD("쿠폰 발급 가능 기간이 아닙니다."), + INVALID_DISCOUNT_COUPON("할인 쿠폰은 결제 시, 사용할 수 있습니다."), + INVALID_BUG_COUPON("벌레 쿠폰은 보관함에서 사용할 수 있습니다."), CONFLICT_COUPON_NAME("쿠폰의 이름이 중복되었습니다."), CONFLICT_COUPON_START_AT("쿠폰 발급 가능 날짜가 중복되었습니다."), NOT_FOUND_COUPON_TYPE("존재하지 않는 쿠폰 종류입니다."), diff --git a/src/main/resources/static/docs/coupon.html b/src/main/resources/static/docs/coupon.html index 4b9cc040..a94f14c3 100644 --- a/src/main/resources/static/docs/coupon.html +++ b/src/main/resources/static/docs/coupon.html @@ -498,7 +498,7 @@

쿠폰 삭제

요청

-
DELETE /admins/coupons/33 HTTP/1.1
+
DELETE /admins/coupons/35 HTTP/1.1
 Host: localhost:8080
@@ -526,7 +526,7 @@

특정 쿠폰 조회

요청

-
GET /coupons/22 HTTP/1.1
+
GET /coupons/23 HTTP/1.1
 Host: localhost:8080
@@ -540,16 +540,16 @@

응답

Access-Control-Allow-Credentials: true Access-Control-Max-Age: 3600 Content-Type: application/json -Content-Length: 205 +Content-Length: 198 { - "id" : 22, + "id" : 23, "adminName" : "1admin", "name" : "couponName", "description" : "", "point" : 10, "stock" : 100, - "type" : "MORNING_COUPON", + "type" : "MORNING", "startAt" : "2023-02-01", "openAt" : "2023-01-01" }
@@ -590,16 +590,16 @@

응답

Access-Control-Allow-Credentials: true Access-Control-Max-Age: 3600 Content-Type: application/json -Content-Length: 206 +Content-Length: 199 [ { - "id" : 23, + "id" : 24, "adminName" : "1admin", "name" : "coupon1", "description" : "", "point" : 10, "stock" : 100, - "type" : "MORNING_COUPON", + "type" : "MORNING", "startAt" : "2023-03-01", "openAt" : "2023-01-01" } ]
@@ -672,38 +672,38 @@

응답

Access-Control-Allow-Credentials: true Access-Control-Max-Age: 3600 Content-Type: application/json -Content-Length: 507 +Content-Length: 472 [ { - "id" : 17, + "id" : 18, "name" : "c1", "description" : "", "point" : 10, - "type" : "MORNING_COUPON" + "type" : "MORNING" }, { - "id" : 18, + "id" : 19, "name" : "c2", "description" : "", "point" : 10, - "type" : "MORNING_COUPON" + "type" : "MORNING" }, { - "id" : 19, + "id" : 20, "name" : "c3", "description" : "", "point" : 10, - "type" : "MORNING_COUPON" + "type" : "MORNING" }, { - "id" : 20, + "id" : 21, "name" : "c4", "description" : "", "point" : 10, - "type" : "MORNING_COUPON" + "type" : "MORNING" }, { - "id" : 21, + "id" : 22, "name" : "c5", "description" : "", "point" : 10, - "type" : "MORNING_COUPON" + "type" : "MORNING" } ] @@ -711,12 +711,34 @@

응답

-

쿠폰 사용 (진행 중)

+

쿠폰을 사용

사용자가 자신의 보관함에 있는 쿠폰들을 사용합니다.
+
+

요청

+
+
+
POST /my-coupons/8 HTTP/1.1
+Host: localhost:8080
+Content-Type: application/x-www-form-urlencoded
+
+
+

응답

+
+
+
HTTP/1.1 200 OK
+Access-Control-Allow-Origin:
+Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
+Access-Control-Allow-Headers: Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers, X-Requested-With,Content-Type, Referer
+Access-Control-Allow-Credentials: true
+Access-Control-Max-Age: 3600
+
+
+
+
@@ -724,7 +746,7 @@

쿠폰 사용 (진행 중)

diff --git a/src/test/java/com/moabam/api/application/bug/BugServiceTest.java b/src/test/java/com/moabam/api/application/bug/BugServiceTest.java index fa075dc6..e2bb6d8e 100644 --- a/src/test/java/com/moabam/api/application/bug/BugServiceTest.java +++ b/src/test/java/com/moabam/api/application/bug/BugServiceTest.java @@ -22,6 +22,7 @@ import com.moabam.api.application.member.MemberService; import com.moabam.api.application.payment.PaymentMapper; import com.moabam.api.domain.bug.Bug; +import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.api.domain.member.Member; import com.moabam.api.domain.payment.Payment; import com.moabam.api.domain.payment.repository.PaymentRepository; @@ -103,7 +104,8 @@ void apply_coupon_success() { PurchaseProductRequest request = new PurchaseProductRequest(couponWalletId); given(productRepository.findById(productId)).willReturn(Optional.of(bugProduct())); given(paymentRepository.save(any(Payment.class))).willReturn(payment); - given(couponService.getByWalletIdAndMemberId(couponWalletId, memberId)).willReturn(discount1000Coupon()); + given(couponService.getWalletByIdAndMemberId(couponWalletId, memberId)).willReturn( + CouponWallet.create(memberId, discount1000Coupon())); // when PurchaseProductResponse response = bugService.purchaseBugProduct(memberId, productId, request); diff --git a/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java b/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java index a8e19049..de7e817e 100644 --- a/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java +++ b/src/test/java/com/moabam/api/application/coupon/CouponServiceTest.java @@ -17,12 +17,15 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import com.moabam.api.application.member.MemberService; import com.moabam.api.domain.coupon.Coupon; import com.moabam.api.domain.coupon.CouponType; import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.api.domain.coupon.repository.CouponRepository; import com.moabam.api.domain.coupon.repository.CouponSearchRepository; +import com.moabam.api.domain.coupon.repository.CouponWalletRepository; import com.moabam.api.domain.coupon.repository.CouponWalletSearchRepository; +import com.moabam.api.domain.member.Member; import com.moabam.api.domain.member.Role; import com.moabam.api.dto.coupon.CouponResponse; import com.moabam.api.dto.coupon.CouponStatusRequest; @@ -37,7 +40,9 @@ import com.moabam.global.error.model.ErrorMessage; import com.moabam.support.annotation.WithMember; import com.moabam.support.common.FilterProcessExtension; +import com.moabam.support.fixture.BugFixture; import com.moabam.support.fixture.CouponFixture; +import com.moabam.support.fixture.MemberFixture; @ExtendWith({MockitoExtension.class, FilterProcessExtension.class}) class CouponServiceTest { @@ -48,9 +53,15 @@ class CouponServiceTest { @Mock CouponManageService couponManageService; + @Mock + MemberService memberService; + @Mock CouponRepository couponRepository; + @Mock + CouponWalletRepository couponWalletRepository; + @Mock CouponSearchRepository couponSearchRepository; @@ -166,7 +177,7 @@ void create_StartAt_BadRequestException() { void create_OpenAt_BadRequestException() { // Given AuthMember admin = AuthorizationThreadLocal.getAuthMember(); - String couponType = CouponType.GOLDEN_COUPON.getName(); + String couponType = CouponType.GOLDEN.getName(); CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 1); given(couponRepository.existsByName(any(String.class))).willReturn(false); @@ -300,9 +311,90 @@ void getByWalletIdAndMemberId_success() { .willReturn(Optional.of(couponWallet)); // When - Coupon actual = couponService.getByWalletIdAndMemberId(1L, 1L); + CouponWallet actual = couponService.getWalletByIdAndMemberId(1L, 1L); + + // Then + assertThat(actual.getCoupon().getName()).isEqualTo(couponWallet.getCoupon().getName()); + } + + @DisplayName("특정 회원이 쿠폰 지갑에 가지고 있는 특정 쿠폰을 성공적으로 사용한다. - Void") + @Test + void use_success() { + // Given + Member member = MemberFixture.member(BugFixture.zeroBug()); + Coupon coupon = CouponFixture.coupon(CouponType.GOLDEN, 1000); + CouponWallet couponWallet = CouponWallet.create(1L, coupon); + + given(memberService.findMember(any(Long.class))).willReturn(member); + given(couponWalletSearchRepository.findByIdAndMemberId(any(Long.class), any(Long.class))) + .willReturn(Optional.of(couponWallet)); + + // When + couponService.use(1L, 1L); + + // Then + verify(couponWalletRepository).delete(any(CouponWallet.class)); + } + + @DisplayName("특정 회원이 쿠폰 지갑에 가지고 있는 할인 쿠폰을 사용한다. - BadRequestException") + @Test + void use_BadRequestException() { + // Given + Coupon coupon = CouponFixture.coupon(CouponType.DISCOUNT, 1000); + CouponWallet couponWallet = CouponWallet.create(1L, coupon); + + given(couponWalletSearchRepository.findByIdAndMemberId(any(Long.class), any(Long.class))) + .willReturn(Optional.of(couponWallet)); + + // When & Then + assertThatThrownBy(() -> couponService.use(1L, 1L)) + .isInstanceOf(BadRequestException.class) + .hasMessage(ErrorMessage.INVALID_DISCOUNT_COUPON.getMessage()); + } + + @DisplayName("특정 회원이 쿠폰 지갑에 가지고 있지 않은 쿠폰을 사용한다. - NotFoundException") + @Test + void use_NotFoundException() { + // Given + given(couponWalletSearchRepository.findByIdAndMemberId(any(Long.class), any(Long.class))) + .willReturn(Optional.empty()); + + // When & Then + assertThatThrownBy(() -> couponService.use(1L, 1L)) + .isInstanceOf(NotFoundException.class) + .hasMessage(ErrorMessage.NOT_FOUND_COUPON_WALLET.getMessage()); + } + + @DisplayName("결제할 때, 할인 쿠폰을 사용한다. - Void") + @Test + void discount_success() { + // Given + Coupon coupon = CouponFixture.coupon(CouponType.DISCOUNT, 1000); + CouponWallet couponWallet = CouponWallet.create(1L, coupon); + + given(couponWalletSearchRepository.findByIdAndMemberId(any(Long.class), any(Long.class))) + .willReturn(Optional.of(couponWallet)); + + // When + couponService.discount(1L, 1L); // Then - assertThat(actual.getName()).isEqualTo(couponWallet.getCoupon().getName()); + verify(couponWalletRepository).delete(couponWallet); + } + + @DisplayName("결제할 때, 벌레 쿠폰을 사용한다. - BadRequestException") + @Test + void discount_BadRequestException() { + // Given + Coupon coupon = CouponFixture.coupon(CouponType.GOLDEN, 1000); + CouponWallet couponWallet = CouponWallet.create(1L, coupon); + + given(couponWalletSearchRepository.findByIdAndMemberId(any(Long.class), any(Long.class))) + .willReturn(Optional.of(couponWallet)); + + // When & Then + assertThatThrownBy(() -> couponService.discount(1L, 1L)) + .isInstanceOf(BadRequestException.class) + .hasMessage(ErrorMessage.INVALID_BUG_COUPON.getMessage()); } } diff --git a/src/test/java/com/moabam/api/application/payment/PaymentServiceTest.java b/src/test/java/com/moabam/api/application/payment/PaymentServiceTest.java index c56e95bf..0f992e1d 100644 --- a/src/test/java/com/moabam/api/application/payment/PaymentServiceTest.java +++ b/src/test/java/com/moabam/api/application/payment/PaymentServiceTest.java @@ -102,7 +102,7 @@ void use_coupon_success() { paymentService.confirm(memberId, request); // then - verify(couponService, times(1)).use(memberId, couponWalletId); + verify(couponService, times(1)).discount(memberId, couponWalletId); verify(bugService, times(1)).charge(memberId, payment.getProduct()); } diff --git a/src/test/java/com/moabam/api/domain/coupon/CouponTest.java b/src/test/java/com/moabam/api/domain/coupon/CouponTest.java index e1e146e3..47dcb2d4 100644 --- a/src/test/java/com/moabam/api/domain/coupon/CouponTest.java +++ b/src/test/java/com/moabam/api/domain/coupon/CouponTest.java @@ -24,7 +24,7 @@ void coupon_success() { Coupon actual = Coupon.builder() .name("couponName") .point(10) - .type(CouponType.MORNING_COUPON) + .type(CouponType.MORNING) .stock(100) .startAt(startAt) .openAt(openAt) @@ -36,7 +36,7 @@ void coupon_success() { assertThat(actual.getDescription()).isBlank(); assertThat(actual.getPoint()).isEqualTo(10); assertThat(actual.getStock()).isEqualTo(100); - assertThat(actual.getType()).isEqualTo(CouponType.MORNING_COUPON); + assertThat(actual.getType()).isEqualTo(CouponType.MORNING); assertThat(actual.getStartAt()).isEqualTo(startAt); assertThat(actual.getOpenAt()).isEqualTo(openAt); assertThat(actual.getAdminId()).isEqualTo(1L); diff --git a/src/test/java/com/moabam/api/domain/coupon/CouponTypeTest.java b/src/test/java/com/moabam/api/domain/coupon/CouponTypeTest.java index 960df900..cf774ca9 100644 --- a/src/test/java/com/moabam/api/domain/coupon/CouponTypeTest.java +++ b/src/test/java/com/moabam/api/domain/coupon/CouponTypeTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import com.moabam.api.domain.bug.BugType; import com.moabam.global.error.exception.NotFoundException; import com.moabam.global.error.model.ErrorMessage; @@ -14,10 +15,10 @@ class CouponTypeTest { @Test void from_success() { // When - CouponType actual = CouponType.from(CouponType.GOLDEN_COUPON.getName()); + CouponType actual = CouponType.from(CouponType.GOLDEN.getName()); // Then - assertThat(actual).isEqualTo(CouponType.GOLDEN_COUPON); + assertThat(actual).isEqualTo(CouponType.GOLDEN); } @DisplayName("존재하지 않는 쿠폰을 가져온다. - NotFoundException") @@ -28,4 +29,24 @@ void from_NotFoundException() { .isInstanceOf(NotFoundException.class) .hasMessage(ErrorMessage.NOT_FOUND_COUPON_TYPE.getMessage()); } + + @DisplayName("할인 쿠폰인 확인한다. - Boolean") + @Test + void isDiscount_true() { + // When + boolean actual = CouponType.DISCOUNT.isDiscount(); + + // Then + assertThat(actual).isTrue(); + } + + @DisplayName("벌레 타입을 반환한다. - CouponType") + @Test + void getBugType_success() { + // When + BugType actual = CouponType.GOLDEN.getBugType(); + + // Then + assertThat(actual).isEqualTo(BugType.GOLDEN); + } } diff --git a/src/test/java/com/moabam/api/domain/coupon/repository/CouponWalletSearchRepositoryTest.java b/src/test/java/com/moabam/api/domain/coupon/repository/CouponWalletSearchRepositoryTest.java index 1d8d6526..82d1fd5c 100644 --- a/src/test/java/com/moabam/api/domain/coupon/repository/CouponWalletSearchRepositoryTest.java +++ b/src/test/java/com/moabam/api/domain/coupon/repository/CouponWalletSearchRepositoryTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.*; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -97,7 +98,7 @@ void findAllByCouponIdAndMemberId_Id3_success(List couponWallets) assertThat(actual).hasSize(3); } - @DisplayName("회원의 특정 쿠폰 지갑을 성공적으로 조회한다.") + @DisplayName("회원의 특정 쿠폰 지갑을 성공적으로 조회한다. - CouponWallet") @Test void findByIdAndMemberId_success() { // given @@ -111,4 +112,14 @@ void findByIdAndMemberId_success() { // then assertThat(actual.getCoupon()).isEqualTo(coupon); } + + @DisplayName("특정 회원의 특정 쿠폰 지갑이 조회되지 않는다. - CouponWallet") + @Test + void findByIdAndMemberId_notFound() { + // When + Optional actual = couponWalletSearchRepository.findByIdAndMemberId(1L, 1L); + + // Then + assertThat(actual).isEmpty(); + } } diff --git a/src/test/java/com/moabam/api/domain/payment/PaymentTest.java b/src/test/java/com/moabam/api/domain/payment/PaymentTest.java index b9ca3d9c..ede0ed7a 100644 --- a/src/test/java/com/moabam/api/domain/payment/PaymentTest.java +++ b/src/test/java/com/moabam/api/domain/payment/PaymentTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test; import com.moabam.api.domain.coupon.Coupon; +import com.moabam.api.domain.coupon.CouponWallet; import com.moabam.global.error.exception.BadRequestException; class PaymentTest { @@ -38,15 +39,14 @@ void success() { // given Payment payment = payment(bugProduct()); Coupon coupon = discount1000Coupon(); - Long couponWalletId = 1L; + CouponWallet couponWallet = CouponWallet.create(1L, coupon); // when - payment.applyCoupon(coupon, couponWalletId); + payment.applyCoupon(couponWallet); // then assertThat(payment.getTotalAmount()).isEqualTo(BUG_PRODUCT_PRICE - 1000); assertThat(payment.getDiscountAmount()).isEqualTo(coupon.getPoint()); - assertThat(payment.getCouponWalletId()).isEqualTo(couponWalletId); } @DisplayName("할인 금액이 더 크면 0으로 처리한다.") @@ -55,10 +55,10 @@ void discount_amount_greater() { // given Payment payment = payment(bugProduct()); Coupon coupon = discount10000Coupon(); - Long couponWalletId = 1L; + CouponWallet couponWallet = CouponWallet.create(1L, coupon); // when - payment.applyCoupon(coupon, couponWalletId); + payment.applyCoupon(couponWallet); // then assertThat(payment.getTotalAmount()).isZero(); diff --git a/src/test/java/com/moabam/api/presentation/CouponControllerTest.java b/src/test/java/com/moabam/api/presentation/CouponControllerTest.java index 880962fb..20965ff5 100644 --- a/src/test/java/com/moabam/api/presentation/CouponControllerTest.java +++ b/src/test/java/com/moabam/api/presentation/CouponControllerTest.java @@ -32,6 +32,7 @@ import com.moabam.api.domain.coupon.repository.CouponRepository; import com.moabam.api.domain.coupon.repository.CouponWalletRepository; import com.moabam.api.domain.member.Role; +import com.moabam.api.domain.member.repository.MemberRepository; import com.moabam.api.dto.coupon.CouponStatusRequest; import com.moabam.api.dto.coupon.CreateCouponRequest; import com.moabam.global.common.util.ClockHolder; @@ -39,6 +40,7 @@ import com.moabam.support.annotation.WithMember; import com.moabam.support.common.WithoutFilterSupporter; import com.moabam.support.fixture.CouponFixture; +import com.moabam.support.fixture.MemberFixture; import com.moabam.support.snippet.CouponSnippet; import com.moabam.support.snippet.CouponWalletSnippet; import com.moabam.support.snippet.ErrorSnippet; @@ -55,6 +57,9 @@ class CouponControllerTest extends WithoutFilterSupporter { @Autowired ObjectMapper objectMapper; + @Autowired + MemberRepository memberRepository; + @Autowired CouponRepository couponRepository; @@ -114,7 +119,7 @@ void create_Coupon_StartAt_BadRequestException() throws Exception { @Test void create_Coupon_OpenAt_BadRequestException() throws Exception { // Given - String couponType = CouponType.GOLDEN_COUPON.getName(); + String couponType = CouponType.GOLDEN.getName(); CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 1); given(clockHolder.date()).willReturn(LocalDate.of(2022, 1, 1)); @@ -442,4 +447,59 @@ void getWallet_no_coupon() throws Exception { .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$", hasSize(0))); } + + @WithMember + @DisplayName("POST - 특정 회원이 보유한 쿠폰을 성공적으로 사용한다. - Void") + @Test + void use_success() throws Exception { + // Given + Coupon coupon = couponRepository.save(CouponFixture.coupon()); + CouponWallet couponWallet = couponWalletRepository.save(CouponWallet.create(1L, coupon)); + memberRepository.save(MemberFixture.member(1L)); + + // When & Then + mockMvc.perform(post("/my-coupons/" + couponWallet.getId())) + .andDo(print()) + .andDo(document("my-coupons/couponWalletId", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()))) + .andExpect(status().isOk()); + } + + @WithMember + @DisplayName("POST - 특정 회원이 보유하지 않은 쿠폰을 사용한다. - NotFoundException") + @Test + void use_NotFoundException() throws Exception { + // When & Then + mockMvc.perform(post("/my-coupons/" + 777L)) + .andDo(print()) + .andDo(document("my-coupons/couponWalletId", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + ErrorSnippet.ERROR_MESSAGE_RESPONSE)) + .andExpect(status().isNotFound()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.message").value(ErrorMessage.NOT_FOUND_COUPON_WALLET.getMessage())); + ; + } + + @WithMember + @DisplayName("POST - 특정 회원이 보유한 할인 쿠폰을 사용한다. - BadRequestException") + @Test + void use_BadRequestException() throws Exception { + // Given + Coupon coupon = couponRepository.save(CouponFixture.coupon(CouponType.DISCOUNT, 1000)); + CouponWallet couponWallet = couponWalletRepository.save(CouponWallet.create(1L, coupon)); + + // When & Then + mockMvc.perform(post("/my-coupons/" + couponWallet.getId())) + .andDo(print()) + .andDo(document("my-coupons/couponWalletId", + preprocessRequest(prettyPrint()), + preprocessResponse(prettyPrint()), + ErrorSnippet.ERROR_MESSAGE_RESPONSE)) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.message").value(ErrorMessage.INVALID_DISCOUNT_COUPON.getMessage())); + } } diff --git a/src/test/java/com/moabam/support/fixture/AuthMemberFixture.java b/src/test/java/com/moabam/support/fixture/AuthMemberFixture.java new file mode 100644 index 00000000..e4a899b2 --- /dev/null +++ b/src/test/java/com/moabam/support/fixture/AuthMemberFixture.java @@ -0,0 +1,11 @@ +package com.moabam.support.fixture; + +import com.moabam.api.domain.member.Member; +import com.moabam.global.auth.model.AuthMember; + +public final class AuthMemberFixture { + + public static AuthMember authMember(Member member) { + return new AuthMember(member.getId(), member.getNickname(), member.getRole()); + } +} diff --git a/src/test/java/com/moabam/support/fixture/BugFixture.java b/src/test/java/com/moabam/support/fixture/BugFixture.java index a6578d40..ec3b82c9 100644 --- a/src/test/java/com/moabam/support/fixture/BugFixture.java +++ b/src/test/java/com/moabam/support/fixture/BugFixture.java @@ -23,6 +23,14 @@ public static Bug bug() { .build(); } + public static Bug zeroBug() { + return Bug.builder() + .morningBug(0) + .nightBug(0) + .goldenBug(0) + .build(); + } + public static BugHistory rewardMorningBugHistory(Long memberId) { return BugHistory.builder() .memberId(memberId) diff --git a/src/test/java/com/moabam/support/fixture/CouponFixture.java b/src/test/java/com/moabam/support/fixture/CouponFixture.java index 1c67661c..871492da 100644 --- a/src/test/java/com/moabam/support/fixture/CouponFixture.java +++ b/src/test/java/com/moabam/support/fixture/CouponFixture.java @@ -24,7 +24,7 @@ public static Coupon coupon() { return Coupon.builder() .name("couponName") .point(1000) - .type(CouponType.MORNING_COUPON) + .type(CouponType.MORNING) .stock(100) .startAt(LocalDate.of(2023, 2, 1)) .openAt(LocalDate.of(2023, 1, 1)) @@ -36,7 +36,7 @@ public static Coupon coupon(String name, int startAt) { return Coupon.builder() .name(name) .point(10) - .type(CouponType.MORNING_COUPON) + .type(CouponType.MORNING) .stock(100) .startAt(LocalDate.of(2023, startAt, 1)) .openAt(LocalDate.of(2023, 1, 1)) @@ -48,7 +48,7 @@ public static Coupon coupon(int point, int stock) { return Coupon.builder() .name("couponName") .point(point) - .type(CouponType.MORNING_COUPON) + .type(CouponType.MORNING) .stock(stock) .startAt(LocalDate.of(2023, 2, 1)) .openAt(LocalDate.of(2023, 1, 1)) @@ -56,11 +56,23 @@ public static Coupon coupon(int point, int stock) { .build(); } + public static Coupon coupon(CouponType couponType, int point) { + return Coupon.builder() + .name("couponName") + .point(point) + .type(couponType) + .stock(100) + .startAt(LocalDate.of(2023, 2, 1)) + .openAt(LocalDate.of(2023, 1, 1)) + .adminId(1L) + .build(); + } + public static Coupon coupon(String name, int startMonth, int openMonth) { return Coupon.builder() .name(name) .point(10) - .type(CouponType.MORNING_COUPON) + .type(CouponType.MORNING) .stock(100) .startAt(LocalDate.of(2023, startMonth, 1)) .openAt(LocalDate.of(2023, openMonth, 1)) @@ -72,7 +84,7 @@ public static Coupon discount1000Coupon() { return Coupon.builder() .name(DISCOUNT_1000_COUPON_NAME) .point(1000) - .type(CouponType.DISCOUNT_COUPON) + .type(CouponType.DISCOUNT) .stock(100) .startAt(LocalDate.of(2023, 2, 1)) .openAt(LocalDate.of(2023, 1, 1)) @@ -84,7 +96,7 @@ public static Coupon discount10000Coupon() { return Coupon.builder() .name(DISCOUNT_10000_COUPON_NAME) .point(10000) - .type(CouponType.DISCOUNT_COUPON) + .type(CouponType.DISCOUNT) .stock(100) .startAt(LocalDate.of(2023, 2, 1)) .openAt(LocalDate.of(2023, 2, 1)) @@ -97,7 +109,7 @@ public static CreateCouponRequest createCouponRequest() { .name("couponName") .description("coupon description") .point(10) - .type(CouponType.GOLDEN_COUPON.getName()) + .type(CouponType.GOLDEN.getName()) .stock(10) .startAt(LocalDate.of(2023, 2, 1)) .openAt(LocalDate.of(2023, 1, 1)) diff --git a/src/test/java/com/moabam/support/fixture/MemberFixture.java b/src/test/java/com/moabam/support/fixture/MemberFixture.java index 50ff801c..3bf73d15 100644 --- a/src/test/java/com/moabam/support/fixture/MemberFixture.java +++ b/src/test/java/com/moabam/support/fixture/MemberFixture.java @@ -1,5 +1,6 @@ package com.moabam.support.fixture; +import com.moabam.api.domain.bug.Bug; import com.moabam.api.domain.member.Member; public final class MemberFixture { @@ -14,6 +15,21 @@ public static Member member() { .build(); } + public static Member member(Long id) { + return Member.builder() + .id(id) + .socialId(SOCIAL_ID) + .bug(BugFixture.bug()) + .build(); + } + + public static Member member(Bug bug) { + return Member.builder() + .socialId(SOCIAL_ID) + .bug(bug) + .build(); + } + public static Member member(String socialId, String nickname) { return Member.builder() .socialId(socialId)