Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

@Repository
public interface OrderRepository extends JpaRepository<Order, UUID> {
Optional<Order> findByOrderId(UUID orderId);
@Query("SELECT o FROM Order o JOIN FETCH o.deliveryAddress da WHERE o.orderId =: orderId")
Comment thread
Bal1oon marked this conversation as resolved.
Outdated
Optional<Order> findOrderWithAddress(@Param("orderId") UUID orderId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.irum.come2us.domain.refund.application.service;

import com.irum.come2us.domain.order.domain.entity.Order;
import com.irum.come2us.domain.order.domain.entity.OrderDetail;
import com.irum.come2us.domain.order.domain.repository.OrderDetailRepository;
import com.irum.come2us.domain.order.domain.repository.OrderRepository;
import com.irum.come2us.domain.refund.domain.entity.Refund;
import com.irum.come2us.domain.refund.domain.entity.enums.RefundStatus;
import com.irum.come2us.domain.refund.domain.repository.RefundRepository;
import com.irum.come2us.domain.refund.presentation.dto.request.RefundCreateRequest;
import com.irum.come2us.domain.refund.presentation.dto.request.StoreRefundStatusRequest;
import com.irum.come2us.domain.refund.presentation.dto.response.*;
import com.irum.come2us.global.presentation.advice.exception.CommonException;
import com.irum.come2us.global.presentation.advice.exception.errorcode.OrderErrorCode;
import com.irum.come2us.global.presentation.advice.exception.errorcode.RefundErrorCode;
import com.irum.come2us.global.util.MemberUtil;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class RefundService {

private final MemberUtil memberUtil;
private final RefundRepository refundRepository;
private final OrderRepository orderRepository;
private final OrderDetailRepository orderDetailRepository;

// Customer
public void createRefund(UUID orderId, RefundCreateRequest request) {
assertNoRefundExistsByOrder(orderId);
Order order = getValidOrder(orderId);
refundRepository.save(
Refund.create(
request.reason(),
request.description(),
order.getPayment().getAmount())); // Payment 도메인 Getter 삽입 필요
Comment thread
Bal1oon marked this conversation as resolved.
Outdated
}
Comment on lines +36 to +43

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: 현재 상태에서는 결제가 완료된 주문에 대해서 환불이 진행되는지에 대한 검증이 없는 거 같아, 결제된 주문인지 검증하는 로직이 추가되어야 할 거 같습니다.

@willjsw willjsw Oct 25, 2025

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 주문에 대한 취소가 가능한 상황은 배송을 기준으로, 배송이 시작되기 전인 것으로 알고 있는데(모든 상품이 준비중, 아직 발송된 상품 X 상태),
OrderStatus 기준 PREPARING 일 때만 취소가 가능한 것으로 처리하면 될까요?
@hyeonji91

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 맞습니다!


@Transactional(readOnly = true)
public RefundDetailResponse findRefundDetail(UUID orderId) {
Order order = getValidOrderWithAddress(orderId);
Refund refund = getValidRefund(orderId);
List<OrderDetail> orderDetails = orderDetailRepository.findAllByOrder(order);
return RefundDetailResponse.of(order, orderDetails, refund);
}

// Owner
@Transactional(readOnly = true)
public StoreRefundListResponse findRefundListByStatus(RefundStatus status) {
List<Refund> refunds = refundRepository.findByRefundStatus(status);

var orderList =
refunds.stream()
.map(
refund -> {
var order = refund.getOrder();
var products = List.<RefundProductList>of();

return new RefundOrderList(
order.getOrderId(),
order.getDeliveryAddress().getRecipientName(),
order.getCreatedAt(),
refund.getCreatedAt(),
refund.getRefundStatus(),
refund.getPrice(),
products);
})
.toList();

int total = refunds.stream().mapToInt(Refund::getPrice).sum();

return new StoreRefundListResponse(orderList, String.valueOf(total), false, null);
}

public void changeRefundStatus(UUID refundId, StoreRefundStatusRequest request) {
Refund refund =
refundRepository
.findById(refundId)
.orElseThrow(() -> new CommonException(RefundErrorCode.REFUND_NOT_FOUND));

refund.updateStatus(request.refundStatus());
Comment thread
Bal1oon marked this conversation as resolved.
}

private void assertNoRefundExistsByOrder(UUID orderId) {
if (refundRepository.existsByOrderId(orderId))
throw new CommonException(RefundErrorCode.REFUND_ALREADY_EXISTS);
}

private Order getValidOrder(UUID orderId) {
Order order =
orderRepository
.findById(orderId)
.orElseThrow(() -> new CommonException(OrderErrorCode.ORDER_NOT_FOUND));
memberUtil.assertMemberResourceAccess(order.getMember());
return order;
}

private Order getValidOrderWithAddress(UUID orderId) {
Order order =
orderRepository
.findOrderWithAddress(orderId)
.orElseThrow(() -> new CommonException(OrderErrorCode.ORDER_NOT_FOUND));
memberUtil.assertMemberResourceAccess(order.getMember());
return order;
}

private Refund getValidRefund(UUID orderId) {
return refundRepository
.findByOrderId(orderId)
.orElseThrow(() -> new CommonException(RefundErrorCode.REFUND_NOT_FOUND));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package com.irum.come2us.domain.refund.domain.repository;

import com.irum.come2us.domain.order.domain.entity.Order;
import com.irum.come2us.domain.refund.domain.entity.Refund;
import com.irum.come2us.domain.refund.domain.entity.enums.RefundStatus;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface RefundRepository extends JpaRepository<Refund, UUID> {
List<Refund> findByRefundStatus(RefundStatus status);
@Query("SELECT COUNT(r)>0 FROM Refund r WHERE r.order.orderId =: orderId")
boolean existsByOrderId(@Param("orderId") UUID orderId);

// RefundRepository 추후 orderRepository에서 가져오는 것으로 변경 예정
// public interface OrderRepository extends JpaRepository<Order, UUID> {..}
Optional<Order> findByOrder_OrderId(@Param("orderId") UUID orderId);
@Query("SELECT r FROM Refund r WHERE r.order.orderId =: orderId")
Optional<Refund> findByOrderId(@Param("orderId") UUID orderId);
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
package com.irum.come2us.domain.refund.presentation.controller;

import com.irum.come2us.domain.refund.application.service.StoreRefundService;
import com.irum.come2us.domain.refund.application.service.RefundService;
import com.irum.come2us.domain.refund.domain.entity.enums.RefundStatus;
import com.irum.come2us.domain.refund.presentation.dto.request.StoreRefundCreateRequest;
import com.irum.come2us.domain.refund.presentation.dto.request.RefundCreateRequest;
import com.irum.come2us.domain.refund.presentation.dto.request.StoreRefundStatusRequest;
import com.irum.come2us.domain.refund.presentation.dto.response.StoreRefundDetailResponse;
import com.irum.come2us.domain.refund.presentation.dto.response.RefundDetailResponse;
import com.irum.come2us.domain.refund.presentation.dto.response.StoreRefundListResponse;
import com.irum.come2us.domain.refund.presentation.dto.response.StoreRefundResponse;
import jakarta.validation.Valid;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/refund/owner")
@RequestMapping("/refund")
@RequiredArgsConstructor
public class StoreRefundController {
private final StoreRefundService refundService;
public class RefundController {
private final RefundService refundService;

// Common
@PostMapping("/{orderId}")
public ResponseEntity<Void> registerRefund(
@PathVariable UUID orderId, @Valid @RequestBody RefundCreateRequest request) {
refundService.createRefund(orderId, request);
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@GetMapping("/{orderId}/detail")
public RefundDetailResponse getRefundDetail(@PathVariable UUID orderId) {
return refundService.findRefundDetail(orderId);
}

// Owner
@PatchMapping("/{refund-id}") // 환불 상태 변경
public ResponseEntity<Void> patchRefundStatus(
@PathVariable("refund-id") UUID refundId,
@RequestBody StoreRefundStatusRequest request) {
refundService.patchRefundStatus(refundId, request);
return ResponseEntity.ok().build();
refundService.changeRefundStatus(refundId, request);
return ResponseEntity.noContent().build();
}

@GetMapping("/list/{refundStatus}") // 환불 요청 목록
public ResponseEntity<StoreRefundListResponse> getRefundList(
public StoreRefundListResponse getRefundList(
@RequestParam(name = "status", required = false) RefundStatus status) {
return ResponseEntity.ok(refundService.getRefundListByStatus(status));
return refundService.findRefundListByStatus(status);
}

// @GetMapping("/list/processing") // 환불 진행중 목록
Expand All @@ -42,17 +57,4 @@ public ResponseEntity<StoreRefundListResponse> getRefundList(
// return ResponseEntity.ok(refundService.getRefundListByStatus(RefundStatus.COMPLETED));
// }

@PostMapping("/{order-id}") // 환불 요청
public ResponseEntity<StoreRefundResponse> createRefund(
@PathVariable("order-id") UUID orderId, @RequestBody StoreRefundCreateRequest request) {
StoreRefundResponse response = refundService.createRefund(orderId, request);
return ResponseEntity.ok().build();
}

@GetMapping("/{refund-id}") // 환불 상세 보기
public ResponseEntity<StoreRefundDetailResponse> getRefundDatil(
@PathVariable("refund-id") UUID refundId) {
StoreRefundDetailResponse response = refundService.getRefundDetail(refundId);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.irum.come2us.domain.refund.presentation.dto.request;

import com.irum.come2us.domain.refund.domain.entity.enums.RefundReason;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;

public record RefundCreateRequest(
@NotNull(message = "환불 사유는 필수 입력값입니다.") RefundReason reason,
@Nullable String description) {}

This file was deleted.

Loading
Loading