Skip to content

Commit

Permalink
feature: 봉달 목록내 상품 제거 api (#37)
Browse files Browse the repository at this point in the history
* feat: 봉달 상품 제거 로직 추가

* feat: 봉달 상품 제거 API 추가

* fix: 봉달 상품 제거시 단일 제거 방식으로 수정

* refactor: api url 수정

* refactor: Delete시 path variable 로 요청 받도록 수정
  • Loading branch information
TaeyeonRoyce authored Feb 2, 2024
1 parent 8271d54 commit c2ad99b
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 10 deletions.
10 changes: 10 additions & 0 deletions src/main/kotlin/com/petqua/application/cart/CartProductService.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.petqua.application.cart

import com.petqua.application.cart.dto.DeleteCartProductCommand
import com.petqua.application.cart.dto.SaveCartProductCommand
import com.petqua.application.cart.dto.UpdateCartProductOptionCommand
import com.petqua.common.domain.existByIdOrThrow
Expand Down Expand Up @@ -66,4 +67,13 @@ class CartProductService(
deliveryMethod = deliveryMethod
)?.also { throw CartProductException(DUPLICATED_PRODUCT) }
}

fun delete(command: DeleteCartProductCommand) {
val cartProduct = cartProductRepository.findByIdOrThrow(
command.cartProductId,
CartProductException(NOT_FOUND_CART_PRODUCT)
)
cartProduct.validateOwner(command.memberId)
cartProductRepository.delete(cartProduct)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ data class UpdateCartProductOptionCommand(
val isMale: Boolean,
val deliveryMethod: DeliveryMethod,
)

data class DeleteCartProductCommand(
val memberId: Long,
val cartProductId: Long,
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ interface CartProductRepository : JpaRepository<CartProduct, Long> {
isMale: Boolean,
deliveryMethod: DeliveryMethod
): CartProduct?

fun findAllByIdIn(ids: List<Long>): List<CartProduct>
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.petqua.presentation.cart

import com.petqua.application.cart.CartProductService
import com.petqua.application.cart.dto.DeleteCartProductCommand
import com.petqua.application.product.dto.ProductDetailResponse
import com.petqua.domain.auth.Auth
import com.petqua.domain.auth.LoginMember
import com.petqua.presentation.cart.dto.SaveCartProductRequest
import com.petqua.presentation.cart.dto.UpdateCartProductOptionRequest
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.DeleteMapping
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
Expand Down Expand Up @@ -35,7 +37,7 @@ class CartProductController(
return ResponseEntity.created(location).build()
}

@PatchMapping("/products/{cartProductId}/options")
@PatchMapping("/{cartProductId}/options")
fun updateOptions(
@Auth loginMember: LoginMember,
@PathVariable cartProductId: Long,
Expand All @@ -45,4 +47,17 @@ class CartProductController(
cartProductService.updateOptions(command)
return ResponseEntity.noContent().build()
}

@DeleteMapping("/{cartProductId}")
fun delete(
@Auth loginMember: LoginMember,
@PathVariable cartProductId: Long
): ResponseEntity<Void> {
val command = DeleteCartProductCommand(
memberId = loginMember.memberId,
cartProductId = cartProductId
)
cartProductService.delete(command)
return ResponseEntity.noContent().build()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.petqua.application.cart

import com.petqua.application.cart.dto.DeleteCartProductCommand
import com.petqua.application.cart.dto.SaveCartProductCommand
import com.petqua.application.cart.dto.UpdateCartProductOptionCommand
import com.petqua.common.domain.findByIdOrThrow
Expand All @@ -11,6 +12,7 @@ import com.petqua.domain.member.MemberRepository
import com.petqua.domain.product.ProductRepository
import com.petqua.exception.cart.CartProductException
import com.petqua.exception.cart.CartProductExceptionType.DUPLICATED_PRODUCT
import com.petqua.exception.cart.CartProductExceptionType.FORBIDDEN_CART_PRODUCT
import com.petqua.exception.cart.CartProductExceptionType.NOT_FOUND_CART_PRODUCT
import com.petqua.exception.member.MemberException
import com.petqua.exception.member.MemberExceptionType.NOT_FOUND_MEMBER
Expand Down Expand Up @@ -62,7 +64,7 @@ class CartProductServiceTest(

When("존재 하지 않는 회원이 요청 하는 경우") {
val command = SaveCartProductCommand(
memberId = 999L,
memberId = Long.MIN_VALUE,
productId = productId,
quantity = 1,
isMale = true,
Expand All @@ -78,7 +80,7 @@ class CartProductServiceTest(
When("존재 하지 않는 상품이 요청 하는 경우") {
val command = SaveCartProductCommand(
memberId = memberId,
productId = 999L,
productId = Long.MIN_VALUE,
quantity = 1,
isMale = true,
deliveryMethod = COMMON,
Expand Down Expand Up @@ -153,7 +155,7 @@ class CartProductServiceTest(

When("존재 하지 않는 장바구니 상품에 수정 요청 하는 경우") {
val command = UpdateCartProductOptionCommand(
cartProductId = 999L,
cartProductId = Long.MIN_VALUE,
memberId = memberId,
quantity = CartProductQuantity(2),
isMale = false,
Expand Down Expand Up @@ -190,6 +192,65 @@ class CartProductServiceTest(
}
}

Given("봉달 상품 삭제 명령으로") {
val productId = productRepository.save(product()).id
val memberId = memberRepository.save(member()).id
val cartProduct = cartProductRepository.save(
cartProduct(
memberId = memberId,
productId = productId,
deliveryMethod = COMMON
)
)

When("봉달 상품을") {
DeleteCartProductCommand(
memberId = memberId,
cartProductId = cartProduct.id
).let(cartProductService::delete)

Then("삭제할 수 있다") {
cartProductRepository.findAll().size shouldBe 0
}
}
}

Given("봉달 상품 삭제시") {
val productId = productRepository.save(product()).id
val memberId = memberRepository.save(member()).id
val cartProduct = cartProductRepository.save(
cartProduct(
memberId = memberId,
productId = productId,
deliveryMethod = COMMON
)
)

When("존재 하지 않는 장바구니 상품에 삭제 요청 하는 경우") {
val command = DeleteCartProductCommand(
memberId = memberId,
cartProductId = Long.MIN_VALUE
)
Then("예외가 발생 한다") {
shouldThrow<CartProductException> {
cartProductService.delete(command)
}.exceptionType() shouldBe NOT_FOUND_CART_PRODUCT
}
}

When("다른 회원이 장바구니 상품을 삭제 하는 경우") {
val command = DeleteCartProductCommand(
memberId = Long.MIN_VALUE,
cartProductId = cartProduct.id
)
Then("예외가 발생 한다") {
shouldThrow<CartProductException> {
cartProductService.delete(command)
}.exceptionType() shouldBe FORBIDDEN_CART_PRODUCT
}
}
}

afterContainer {
dataCleaner.clean()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ fun requestSaveCartProduct(
}
}

fun saveCartProductAndReturnId(accessToken: String): Long {
fun saveCartProductAndReturnId(accessToken: String, productId: Long = 1L): Long {
val sampleCartProduct = SaveCartProductRequest(
productId = 1L,
productId = productId,
quantity = 1,
isMale = true,
deliveryMethod = "COMMON"
Expand All @@ -53,7 +53,24 @@ fun requestUpdateCartProductOption(
.header(HttpHeaders.AUTHORIZATION, accessToken)
.contentType("application/json")
} When {
patch("/carts/products/{cartProductId}/options", cartProductId)
patch("/carts/{cartProductId}/options", cartProductId)
} Then {
log().all()
} Extract {
response()
}
}

fun requestDeleteCartProduct(
deleteProductId: Long,
accessToken: String
): Response {
return Given {
log().all()
.header(HttpHeaders.AUTHORIZATION, accessToken)
.contentType("application/json")
} When {
delete("/carts/{cartProductId}", deleteProductId)
} Then {
log().all()
} Extract {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ class CartProductControllerTest(
}

Given("봉달 상품의 옵션 수정을") {
productRepository.save(product(id = 1L))
val savedProduct = productRepository.save(product(id = 1L))
val memberAuthResponse = signInAsMember()
val cartProductId = saveCartProductAndReturnId(memberAuthResponse.accessToken)
val cartProductId = saveCartProductAndReturnId(memberAuthResponse.accessToken, savedProduct.id)

When("요청 하면") {
val request = UpdateCartProductOptionRequest(
Expand All @@ -151,7 +151,7 @@ class CartProductControllerTest(
Given("봉달 상품의 옵션 수정시") {
val savedProduct = productRepository.save(product(id = 1L))
val memberAuthResponse = signInAsMember()
val cartProductId = saveCartProductAndReturnId(memberAuthResponse.accessToken)
val cartProductId = saveCartProductAndReturnId(memberAuthResponse.accessToken, savedProduct.id)

When("존재하지 않는 봉달 상품 수정을 요청 하면") {
val request = UpdateCartProductOptionRequest(
Expand Down Expand Up @@ -273,5 +273,60 @@ class CartProductControllerTest(
}
}
}

Given("봉달 상품 삭제를") {
val product = productRepository.save(product(id = 1L))
val memberAuthResponse = signInAsMember()
val cartProductAId = saveCartProductAndReturnId(memberAuthResponse.accessToken, product.id)


When("요청 하면") {
val response = requestDeleteCartProduct(
cartProductAId,
memberAuthResponse.accessToken
)

Then("봉달 상품이 삭제된다") {
assertThat(response.statusCode).isEqualTo(NO_CONTENT.value())
}
}
}

Given("봉달 상품 삭제시") {
val product = productRepository.save(product(id = 1L))
val memberAuthResponse = signInAsMember()
val cartProductAId = saveCartProductAndReturnId(memberAuthResponse.accessToken, product.id)

When("존재하지 않는 봉달 상품 삭제를 요청 하면") {
val response = requestDeleteCartProduct(
Long.MIN_VALUE,
memberAuthResponse.accessToken
)

Then("예외가 발생한다") {
val errorResponse = response.`as`(ExceptionResponse::class.java)
assertSoftly {
it.assertThat(response.statusCode).isEqualTo(NOT_FOUND.value())
it.assertThat(errorResponse.message).isEqualTo(NOT_FOUND_CART_PRODUCT.errorMessage())
}
}
}

When("다른 회원의 상품을 삭제 하면") {
val otherMemberResponse = signInAsMember()
val response = requestDeleteCartProduct(
cartProductAId,
otherMemberResponse.accessToken
)

Then("예외가 발생한다") {
val errorResponse = response.`as`(ExceptionResponse::class.java)
assertSoftly {
it.assertThat(response.statusCode).isEqualTo(FORBIDDEN.value())
it.assertThat(errorResponse.message).isEqualTo(FORBIDDEN_CART_PRODUCT.errorMessage())
}
}
}
}
}
}

0 comments on commit c2ad99b

Please sign in to comment.