Skip to content

Commit

Permalink
Merge pull request #16 from ClothingStoreService/feature/order-create
Browse files Browse the repository at this point in the history
Feature/order create
  • Loading branch information
axhtl authored Aug 11, 2024
2 parents 9fa11ce + 9aa77e4 commit 6fc5dbe
Show file tree
Hide file tree
Showing 65 changed files with 660 additions and 292 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.store.clothstar.category.dto.request

import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.NotBlank
import org.store.clothstar.category.domain.Category

class CreateCategoryRequest(
@Schema(description = "카테고리 타입(이름)", nullable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import org.springframework.web.bind.annotation.RestControllerAdvice
import org.store.clothstar.common.dto.ErrorResponseDTO
import org.store.clothstar.common.dto.ValidErrorResponseDTO
import org.store.clothstar.common.error.exception.*
import org.store.clothstar.common.error.exception.order.InsufficientStockException
import org.store.clothstar.common.error.exception.order.InvalidOrderStatusException
import org.store.clothstar.common.error.exception.order.OrderNotFoundException
import org.store.clothstar.common.error.exception.order.OutOfStockException
import java.util.function.Consumer

@RestControllerAdvice
Expand Down Expand Up @@ -182,6 +184,12 @@ class GlobalExceptionHandler {
return ResponseEntity(errorResponseDTO, HttpStatus.INTERNAL_SERVER_ERROR)
}

@ExceptionHandler(NotFoundAddressException::class)
fun handleAddressNotFoundException(ex: NotFoundAddressException): ResponseEntity<ErrorResponseDTO> {
val errorResponseDTO = ErrorResponseDTO(ex.errorCode.status.value(), ex.errorCode.message)
return ResponseEntity(errorResponseDTO, ex.errorCode.status)
}

// Order 관련 에러처리
@ExceptionHandler(OrderNotFoundException::class)
fun handleOrderNotFoundException(ex: OrderNotFoundException): ResponseEntity<ErrorResponseDTO> {
Expand All @@ -194,4 +202,16 @@ class GlobalExceptionHandler {
val errorResponseDTO = ErrorResponseDTO(ex.errorCode.status.value(), ex.errorCode.message)
return ResponseEntity(errorResponseDTO, ex.errorCode.status)
}

@ExceptionHandler(InsufficientStockException::class)
fun handleInsufficientStockException(ex: InsufficientStockException): ResponseEntity<ErrorResponseDTO> {
val errorResponseDTO = ErrorResponseDTO(ex.errorCode.status.value(), ex.errorCode.message)
return ResponseEntity(errorResponseDTO, ex.errorCode.status)
}

@ExceptionHandler(OutOfStockException::class)
fun handleOutOfStockExceptionException(ex: OutOfStockException): ResponseEntity<ErrorResponseDTO> {
val errorResponseDTO = ErrorResponseDTO(ex.errorCode.status.value(), ex.errorCode.message)
return ResponseEntity(errorResponseDTO, ex.errorCode.status)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ open class BaseEntity(
@CreatedDate
var createdAt: LocalDateTime = LocalDateTime.now(),
@LastModifiedDate
var updatedAt: LocalDateTime = LocalDateTime.now(),
var updatedAt: LocalDateTime? = null,
var deletedAt: LocalDateTime? = null,
) {
fun updateDeletedAt() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum class ErrorCode(
) {
NOT_FOUND_ACCOUNT(HttpStatus.NOT_FOUND, "회원 정보를 찾을 수 없습니다."),
NOT_FOUND_MEMBER(HttpStatus.NOT_FOUND, "멤버 정보를 찾을 수 없습니다."),
NOT_FOUND_ADDRESS(HttpStatus.NOT_FOUND, "배송지 정보를 찾을 수 없습니다."),

DUPLICATED_EMAIL(HttpStatus.BAD_REQUEST, "이미 사용중인 이메일 입니다."),
DUPLICATED_SELLER(HttpStatus.BAD_REQUEST, "이미 판매자 가입이 되어 있습니다."),
Expand All @@ -21,7 +22,10 @@ enum class ErrorCode(

// Order 관련 에러코드
NOT_FOUND_ORDER(HttpStatus.NOT_FOUND, "존재하지 않는 주문번호입니다."),
INVALID_ORDER_STATUS_CONFIRMED(HttpStatus.BAD_REQUEST, "주문이 입금확인 상태가 아니므로 요청을 처리할 수 없습니다.");
INVALID_ORDER_STATUS_CONFIRMED(HttpStatus.BAD_REQUEST, "주문이 입금확인 상태가 아니므로 요청을 처리할 수 없습니다."),
OUT_OF_STOCK(HttpStatus.BAD_REQUEST, "품절된 상품입니다."),
INSUFFICIENT_STOCK(HttpStatus.BAD_REQUEST, "주문 개수가 상품 재고보다 더 많아 요청을 처리할 수 없습니다.");


fun ErrorCode(status: HttpStatus, message: String) {
this.status = status
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.store.clothstar.common.error.exception

import org.store.clothstar.common.error.ErrorCode

class NotFoundAddressException(
val errorCode: ErrorCode
) : RuntimeException(errorCode.message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.store.clothstar.common.error.exception.order

import org.store.clothstar.common.error.ErrorCode

class InsufficientStockException(
val errorCode: ErrorCode
) : RuntimeException(errorCode.message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.store.clothstar.common.error.exception.order

import org.store.clothstar.common.error.ErrorCode

class OutOfStockException(
val errorCode: ErrorCode
) : RuntimeException(errorCode.message)
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,4 @@ import org.store.clothstar.member.domain.Address
interface AddressRepository : JpaRepository<Address, Long> {
@Query("SELECT addr FROM address addr WHERE addr.memberId = :memberId")
fun findAddressListByMemberId(@Param("memberId") memberId: Long): List<Address?>

fun findByAddressId(addressId: Long): Address?
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package org.store.clothstar.member.service

import org.springframework.http.HttpStatus
import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.server.ResponseStatusException
import org.store.clothstar.common.error.ErrorCode
import org.store.clothstar.common.error.exception.NotFoundAddressException
import org.store.clothstar.common.error.exception.NotFoundMemberException
import org.store.clothstar.member.domain.Address
import org.store.clothstar.member.domain.vo.AddressInfo
Expand Down Expand Up @@ -38,12 +39,6 @@ class AddressServiceImpl(
}
}

@Transactional(readOnly = true)
override fun getAddressById(addressId: Long): Address {
return addressRepository.findByAddressId(addressId)
?: throw ResponseStatusException(HttpStatus.NOT_FOUND, "배송지 정보를 찾을 수 없습니다.")
}

@Transactional
override fun addrSave(memberId: Long, createAddressRequest: CreateAddressRequest): Long {
memberRepository.findByMemberId(memberId)
Expand All @@ -60,9 +55,13 @@ class AddressServiceImpl(
telNo = createAddressRequest.telNo,
memberId = memberId
)

addressRepository.save(address)

return address.addressId!!
}

override fun getAddressById(addressId: Long): Address {
return addressRepository.findByIdOrNull(addressId)
?: throw NotFoundAddressException(ErrorCode.NOT_FOUND_ADDRESS)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,6 @@ class MemberServiceImpl(
}
}

@Transactional(readOnly = true)
override fun getMemberByMemberId(memberId: Long): Member {
return memberRepository.findByIdOrNull(memberId)
?: throw NotFoundMemberException(ErrorCode.NOT_FOUND_MEMBER)
}

@Transactional
override fun modifyName(memberId: Long, modifyNameRequest: ModifyNameRequest) {
log.info { "회원 이름 수정 memberId = ${memberId}, name = ${modifyNameRequest.name}" }
Expand Down Expand Up @@ -146,4 +140,9 @@ class MemberServiceImpl(
throw DuplicatedTelNoException(ErrorCode.DUPLICATED_TEL_NO)
}
}

override fun getMemberByMemberId(memberId: Long): Member {
return memberRepository.findByIdOrNull(memberId)
?: throw NotFoundMemberException(ErrorCode.NOT_FOUND_MEMBER)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package org.store.clothstar.order.controller
//package org.store.clothstar.order.controller

import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.web.bind.annotation.RestController
import org.store.clothstar.order.service.OrderDetailService

@Tag(name = "OrderDetail", description = "주문 내 개별 상품에 대한 옵션, 수량 등을 나타내는, 주문상세(OrderDetail) 정보 관리에 대한 API 입니다.")
@RestController
class OrderDetailController(
private val orderDetailService: OrderDetailService,
) {
//@Tag(name = "OrderDetail", description = "주문 내 개별 상품에 대한 옵션, 수량 등을 나타내는, 주문상세(OrderDetail) 정보 관리에 대한 API 입니다.")
//@RestController
//class OrderDetailController(
// private val orderDetailService: OrderDetailService,
//) {
// @Operation(summary = "주문상세 추가 저장", description = "개별 상품에 대한 주문상세(상품명, 가격, 개수...)를 특정 주문에 추가 저장한다.")
// @PostMapping
// fun addOrderDetail(@RequestBody @Validated addOrderDetailRequest: AddOrderDetailRequest): ResponseEntity<SaveResponseDTO> {
// fun addOrderDetail(@RequestBody @Validated addOrderDetailRequest: AddOrderDetailRequest): ResponseEntity<String> {
// val orderDetailId = orderDetailService.addOrderDetail(addOrderDetailRequest)
//
// return ResponseEntity.ok(
Expand All @@ -20,11 +16,4 @@ class OrderDetailController(
// )
// )
// }
//
// @Operation(summary = "주문상세 삭제", description = "주문상세 삭제시간을 현재시간으로 업데이트 한다.")
// @DeleteMapping("{orderDetailId}")
// fun deleteOrderDetail(@PathVariable orderDetailId: Long): ResponseEntity<MessageDTO> {
// orderDetailService.updateDeleteAt(orderDetailId)
// return ResponseEntity.ok(MessageDTO(HttpStatus.OK.value(), "주문상세가 정상적으로 삭제되었습니다."))
// }
}
//}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class OrderSellerController(
]
)
@PatchMapping("/{orderId}/process")
fun approveOrder(@PathVariable orderId: Long): ResponseEntity<MessageDTO> {
fun approveOrder(@PathVariable orderId: String): ResponseEntity<MessageDTO> {
orderSellerService.approveOrder(orderId)
val messageDTO = MessageDTO(HttpStatus.OK.value(), "주문이 정상적으로 출고처리 되었습니다.")
return ResponseEntity.ok(messageDTO)
Expand All @@ -70,7 +70,7 @@ class OrderSellerController(
]
)
@PatchMapping("/{orderId}/cancel")
fun cancelOrder(@PathVariable orderId: Long): ResponseEntity<MessageDTO> {
fun cancelOrder(@PathVariable orderId: String): ResponseEntity<MessageDTO> {
orderSellerService.cancelOrder(orderId)
val messageDTO = MessageDTO(HttpStatus.OK.value(), "주문이 정상적으로 취소 되었습니다.")
return ResponseEntity.ok(messageDTO)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.store.clothstar.order.controller

import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.validation.annotation.Validated
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.store.clothstar.common.dto.ErrorResponseDTO
import org.store.clothstar.common.dto.MessageDTO
import org.store.clothstar.order.dto.request.OrderRequestWrapper
import org.store.clothstar.order.dto.response.SaveOrderResponse
import org.store.clothstar.order.service.OrderService

@Tag(name = "Order", description = "주문(Order) 정보 관리에 대한 API 입니다.")
@RestController
@RequestMapping("/v1/orders")
class OrderUserController(
private val orderService: OrderService
) {
@Operation(summary = "주문 생성", description = "단일 주문을 생성한다.")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200", description = "주문이 정상적으로 생성되었습니다.",
content = [Content(schema = Schema(implementation = SaveOrderResponse::class))]
),
ApiResponse(
responseCode = "400", description = "품절된 상품입니다.",
content = [Content(schema = Schema(implementation = ErrorResponseDTO::class))]
),
ApiResponse(
responseCode = "400", description = "주문 개수가 상품 재고보다 더 많아 요청을 처리할 수 없습니다.",
content = [Content(schema = Schema(implementation = ErrorResponseDTO::class))]
),
]
)
@PostMapping
fun saveOrder(@RequestBody @Validated orderRequestWrapper: OrderRequestWrapper): ResponseEntity<SaveOrderResponse> {
val orderId: String = orderService.saveOrder(orderRequestWrapper)
val saveOrderResponse = SaveOrderResponse(orderId, HttpStatus.OK.value(), "주문이 정상적으로 생성되었습니다.")
return ResponseEntity.ok(saveOrderResponse)
}
}
11 changes: 8 additions & 3 deletions src/main/kotlin/org/store/clothstar/order/domain/Order.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ package org.store.clothstar.order.domain
import jakarta.persistence.*
import org.store.clothstar.common.entity.BaseEntity
import org.store.clothstar.common.error.ErrorCode
import org.store.clothstar.common.error.exception.order.InvalidOrderStatusException
import org.store.clothstar.common.error.exception.order.OrderNotFoundException
import org.store.clothstar.order.domain.vo.PaymentMethod
import org.store.clothstar.order.domain.vo.Status
import org.store.clothstar.order.domain.vo.TotalPrice
import org.store.clothstar.common.error.exception.order.InvalidOrderStatusException
import org.store.clothstar.common.error.exception.order.OrderNotFoundException

@Entity(name = "orders")
class Order(
@Id
val orderId: Long,
val orderId: String,

@Column(nullable = false)
val memberId: Long,
Expand Down Expand Up @@ -47,4 +47,9 @@ class Order(
throw InvalidOrderStatusException(ErrorCode.INVALID_ORDER_STATUS_CONFIRMED)
}
}

fun addOrderDetail(orderDetail: OrderDetail) {
orderDetails.add(orderDetail)
orderDetail.updateOrder(this)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class OrderDetail(
@JoinColumn(name = "order_id")
var order: Order
) : BaseEntity() {

fun updateOrder(order: Order) {
this.order = order
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import io.swagger.v3.oas.annotations.media.Schema
@Schema(description = "배송지 정보")
class AddressDTO(
@Schema(description = "수령인 이름", example = "수빈")
private val receiverName: String,
val receiverName: String,

@Schema(description = "기본 주소", example = "서울시 강남구")
private val addressBasic: String,
val addressBasic: String,

@Schema(description = "상세 주소", example = "123-456")
private val addressDetail: String,
val addressDetail: String,

@Schema(description = "전화번호", example = "010-1234-5678")
private val telNo: String,
val telNo: String,

@Schema(description = "배송 요청 사항", example = "문 앞에 놓아주세요.")
private val deliveryRequest: String,
val deliveryRequest: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import org.store.clothstar.product.domain.Item
import org.store.clothstar.product.domain.Product

class OrderDetailDTO(
private val orderDetailId: Long,
private val productName: String, // 상품명
private val optionName: String,
private val brandName: String,
private val productPrice: Int = 0, // 고정된 상품 가격 ( 주문 당시 가격 )
private val extraCharge: Int = 0,
private val quantity: Int = 0,
private val totalPrice: Int = 0, // 상품 종류 하나당 총 가격
val orderDetailId: Long,
val productName: String, // 상품명
val optionName: String,
val brandName: String,
val productPrice: Int = 0, // 고정된 상품 가격 ( 주문 당시 가격 )
val extraCharge: Int = 0,
val quantity: Int = 0,
val totalPrice: Int = 0, // 상품 종류 하나당 총 가격
) {
companion object {
fun from(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ data class TotalPrice(
@Column(name = "total_payment_price", nullable = false)
var payment: Int = 0
) {
fun updatePrices(totalProductsPrice: Int, totalPaymentPrice: Int) {
this.products = totalProductsPrice
this.payment = totalPaymentPrice
fun updatePrices(updatedtotalProductsPrice: Int, updatedtotalPaymentPrice: Int) {
this.products = updatedtotalProductsPrice
this.payment = updatedtotalPaymentPrice
}
}
Loading

0 comments on commit 6fc5dbe

Please sign in to comment.