-
Notifications
You must be signed in to change notification settings - Fork 0
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
feature: 봉달목록에 상품 추가 api #31
The head ref may contain hidden characters: "25-feature-\uBD09\uB2EC\uBAA9\uB85D\uC5D0-\uC0C1\uD488-\uCD94\uAC00-api"
Changes from 19 commits
6100145
042708b
08c5168
28bf424
31f9f2d
839b8dc
e0bf5b3
9f677d7
d942e40
82b7dec
6fa783d
842404e
830ac68
c6e37a6
e67b0fc
2348e94
d0a9c55
18e179f
b53c1f4
096a109
5712afa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.petqua.application.cart | ||
|
||
import com.petqua.application.cart.dto.SaveCartProductCommand | ||
import com.petqua.common.domain.existByIdOrThrow | ||
import com.petqua.domain.cart.CartProductRepository | ||
import com.petqua.domain.member.MemberRepository | ||
import com.petqua.domain.product.ProductRepository | ||
import com.petqua.exception.member.MemberException | ||
import com.petqua.exception.member.MemberExceptionType.NOT_FOUND_MEMBER | ||
import com.petqua.exception.product.ProductException | ||
import com.petqua.exception.product.ProductExceptionType.NOT_FOUND_PRODUCT | ||
import org.springframework.stereotype.Service | ||
import org.springframework.transaction.annotation.Transactional | ||
|
||
@Transactional | ||
@Service | ||
class CartProductService( | ||
private val cartProductRepository: CartProductRepository, | ||
private val productRepository: ProductRepository, | ||
private val memberRepository: MemberRepository, | ||
) { | ||
|
||
fun save(command: SaveCartProductCommand): Long { | ||
memberRepository.existByIdOrThrow(command.memberId, MemberException(NOT_FOUND_MEMBER)) | ||
productRepository.existByIdOrThrow(command.productId, ProductException(NOT_FOUND_PRODUCT)) | ||
val savedCartProduct = cartProductRepository.save(command.toCartProduct()) | ||
return savedCartProduct.id | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.petqua.application.cart.dto | ||
|
||
import com.petqua.domain.cart.CartProduct | ||
import com.petqua.domain.cart.CartProductQuantity | ||
import com.petqua.domain.cart.DeliveryMethod | ||
|
||
data class SaveCartProductCommand( | ||
val memberId: Long, | ||
val productId: Long, | ||
val quantity: Int, | ||
val isMale: Boolean, | ||
val deliveryMethod: DeliveryMethod, | ||
) { | ||
fun toCartProduct(): CartProduct { | ||
return CartProduct( | ||
memberId = memberId, | ||
productId = productId, | ||
quantity = CartProductQuantity(quantity), | ||
isMale = isMale, | ||
deliveryMethod = deliveryMethod, | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.petqua.common.util | ||
|
||
inline fun throwExceptionWhen(condition: Boolean, exceptionSupplier: () -> RuntimeException) { | ||
if (condition) throw exceptionSupplier() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.petqua.domain.cart | ||
|
||
import com.petqua.common.domain.BaseEntity | ||
import jakarta.persistence.Column | ||
import jakarta.persistence.Embedded | ||
import jakarta.persistence.Entity | ||
import jakarta.persistence.EnumType | ||
import jakarta.persistence.Enumerated | ||
import jakarta.persistence.GeneratedValue | ||
import jakarta.persistence.GenerationType | ||
import jakarta.persistence.Id | ||
|
||
@Entity | ||
class CartProduct( | ||
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
val id: Long = 0L, | ||
|
||
@Column(nullable = false) | ||
val memberId: Long, | ||
|
||
@Column(nullable = false) | ||
val productId: Long, | ||
|
||
@Embedded | ||
val quantity: CartProductQuantity, | ||
|
||
@Column(nullable = false) | ||
val isMale: Boolean, | ||
|
||
@Enumerated(value = EnumType.STRING) | ||
@Column(nullable = false) | ||
val deliveryMethod: DeliveryMethod, | ||
) : BaseEntity() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.petqua.domain.cart | ||
|
||
import com.petqua.common.util.throwExceptionWhen | ||
import com.petqua.exception.cart.CartProductException | ||
import com.petqua.exception.cart.CartProductExceptionType.PRODUCT_QUANTITY_OVER_MAXIMUM | ||
import com.petqua.exception.cart.CartProductExceptionType.PRODUCT_QUANTITY_UNDER_MINIMUM | ||
import jakarta.persistence.Column | ||
import jakarta.persistence.Embeddable | ||
|
||
private const val MIN_QUANTITY = 1 | ||
private const val MAX_QUANTITY = 99 | ||
|
||
@Embeddable | ||
class CartProductQuantity( | ||
@Column(nullable = false) | ||
val quantity: Int = 1, | ||
) { | ||
|
||
init { | ||
throwExceptionWhen(quantity < MIN_QUANTITY) { CartProductException(PRODUCT_QUANTITY_UNDER_MINIMUM) } | ||
throwExceptionWhen(quantity > MAX_QUANTITY) { CartProductException(PRODUCT_QUANTITY_OVER_MAXIMUM) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.petqua.domain.cart | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository | ||
|
||
interface CartProductRepository : JpaRepository<CartProduct, Long> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.petqua.domain.cart | ||
|
||
import com.petqua.exception.cart.CartProductException | ||
import com.petqua.exception.cart.CartProductExceptionType.INVALID_DELIVERY_METHOD | ||
import java.util.Locale.ENGLISH | ||
|
||
enum class DeliveryMethod( | ||
val description: String, | ||
) { | ||
|
||
COMMON("일반 운송"), | ||
SAFETY("안전 운송"), | ||
PICK_UP("직접 방문"), | ||
; | ||
|
||
companion object { | ||
fun from(name: String): DeliveryMethod { | ||
return enumValues<DeliveryMethod>().find { it.name == name.uppercase(ENGLISH) } | ||
?: throw CartProductException(INVALID_DELIVERY_METHOD) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.petqua.exception.cart | ||
|
||
import com.petqua.common.exception.BaseException | ||
import com.petqua.common.exception.BaseExceptionType | ||
|
||
class CartProductException( | ||
private val exceptionType: CartProductExceptionType, | ||
) : BaseException() { | ||
|
||
override fun exceptionType(): BaseExceptionType { | ||
return exceptionType | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.petqua.exception.cart | ||
|
||
import com.petqua.common.exception.BaseExceptionType | ||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.HttpStatus.BAD_REQUEST | ||
|
||
enum class CartProductExceptionType( | ||
private val httpStatus: HttpStatus, | ||
private val errorMessage: String, | ||
) : BaseExceptionType { | ||
|
||
INVALID_DELIVERY_METHOD(httpStatus = BAD_REQUEST, errorMessage = "유효하지 않는 배송 방법입니다."), | ||
PRODUCT_QUANTITY_UNDER_MINIMUM(httpStatus = BAD_REQUEST, errorMessage = "최소 1개 이상의 상품을 담을 수 있습니다."), | ||
PRODUCT_QUANTITY_OVER_MAXIMUM(httpStatus = BAD_REQUEST, errorMessage = "최대 99개까지 구매할 수 있습니다."), | ||
; | ||
|
||
override fun httpStatus(): HttpStatus { | ||
return httpStatus | ||
} | ||
|
||
override fun errorMessage(): String { | ||
return errorMessage | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.petqua.exception.member | ||
|
||
import com.petqua.common.exception.BaseException | ||
import com.petqua.common.exception.BaseExceptionType | ||
|
||
class MemberException( | ||
private val exceptionType: MemberExceptionType, | ||
) : BaseException() { | ||
|
||
override fun exceptionType(): BaseExceptionType { | ||
return exceptionType | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.petqua.exception.member | ||
|
||
import com.petqua.common.exception.BaseExceptionType | ||
import org.springframework.http.HttpStatus | ||
import org.springframework.http.HttpStatus.NOT_FOUND | ||
|
||
enum class MemberExceptionType( | ||
private val httpStatus: HttpStatus, | ||
private val errorMessage: String, | ||
) : BaseExceptionType { | ||
|
||
NOT_FOUND_MEMBER(NOT_FOUND, "존재하지 않는 회원입니다."), | ||
; | ||
|
||
override fun httpStatus(): HttpStatus { | ||
return httpStatus | ||
} | ||
|
||
override fun errorMessage(): String { | ||
return errorMessage | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.petqua.presentation.cart | ||
|
||
import com.petqua.application.cart.CartProductService | ||
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 org.springframework.http.ResponseEntity | ||
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.RestController | ||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder | ||
|
||
@RequestMapping("/carts") | ||
@RestController | ||
class CartProductController( | ||
private val cartProductService: CartProductService, | ||
) { | ||
|
||
@PostMapping | ||
fun save( | ||
@Auth loginMember: LoginMember, | ||
@RequestBody request: SaveCartProductRequest | ||
): ResponseEntity<ProductDetailResponse> { | ||
val command = request.toCommand(loginMember.memberId) | ||
val cartProductId = cartProductService.save(command) | ||
val location = ServletUriComponentsBuilder.fromCurrentRequest() | ||
.path("/items/{id}") | ||
.buildAndExpand(cartProductId) | ||
.toUri() | ||
return ResponseEntity.created(location).build() | ||
Comment on lines
+28
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 친구는 무엇인가요? ResponseEntity.created(URI.create("/carts" + cartProductId)).build(); 위 코드와 같은 걸까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Location 헤더에 값이 달라져요!
생성된 자원에 대해 접근가능한 URL을 제공하려고 사용했어요!! |
||
} | ||
} |
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.
앗 근데 장바구니에 같은 상품이 두 개 저장될 수 있나요? 보통 이미 동일한 상품이 장바구니에 존재하면 수량만 늘어났던 것 같아서요! 이 부분 펫쿠아 룰을 모르겠네요...
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.
엇 그렇네요. 이미 담긴 상품에 대해서 추가하는 경우에 대한 정책을 생각 못했네요..
이 부분 스크럼때 여쭤보고 반영 할게요!
감사합니다👍