Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -14,4 +14,6 @@ public interface DeliveryRepository extends JpaRepository<Delivery, Long> {
boolean existsDeliveryByOrderId(Long orderId);

Optional<Delivery> findTopByOrder_IdOrderByIdDesc(Long orderId);

void deleteByOrder_Id(Long orderId);
}
4 changes: 4 additions & 0 deletions src/main/java/org/sopt/poti/domain/order/entity/Order.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,8 @@ public void completeDelivery() {
this.status = OrderStatus.DELIVERED;
}

public void updateStatus(OrderStatus status) {
this.status = status;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
public interface PaymentRepository extends JpaRepository<Payment, Long> {

boolean existsByOrder_Id(Long orderId);

void deleteByOrder_Id(Long orderId);
}
15 changes: 15 additions & 0 deletions src/main/java/org/sopt/poti/global/dev/DevController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.RequiredArgsConstructor;
import org.sopt.poti.domain.auth.entity.RefreshToken;
import org.sopt.poti.domain.auth.repository.RefreshTokenRepository;
import org.sopt.poti.domain.order.entity.OrderStatus;
import org.sopt.poti.domain.user.entity.User;
import org.sopt.poti.domain.user.service.UserService;
import org.sopt.poti.global.common.ApiResponse;
Expand All @@ -18,6 +19,8 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -72,4 +75,16 @@ public ResponseEntity<ApiResponse<Void>> hardDeleteMe(
ApiResponse.success(SuccessStatus.OK)
);
}

@PatchMapping("/orders/{orderId}/status")
@Operation(summary = "주문 상태 강제 변경", description = "테스트를 위해 특정 주문의 상태를 강제로 변경합니다. (WAIT_PAY로 변경 시 연관 데이터 삭제됨)")
public ResponseEntity<ApiResponse<Void>> resetOrderStatus(
@PathVariable Long orderId,
@RequestParam OrderStatus status
) {
devService.resetOrderStatus(orderId, status);
return ResponseEntity.ok(
ApiResponse.success(SuccessStatus.OK)
);
}
}
32 changes: 31 additions & 1 deletion src/main/java/org/sopt/poti/global/dev/DevService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.sopt.poti.domain.delivery.repository.DeliveryRepository;
import org.sopt.poti.domain.groupbuy.entity.GroupBuyOption;
import org.sopt.poti.domain.groupbuy.entity.GroupBuyPost;
import org.sopt.poti.domain.groupbuy.repository.GroupBuyRepository;
import org.sopt.poti.domain.order.entity.Order;
import org.sopt.poti.domain.order.entity.OrderStatus;
import org.sopt.poti.domain.order.repository.OrderItemRepository;
import org.sopt.poti.domain.order.repository.OrderRepository;
import org.sopt.poti.domain.payment.repository.PaymentRepository;
import org.sopt.poti.domain.user.repository.UserRepository;
import org.sopt.poti.global.error.BusinessException;
import org.sopt.poti.global.error.ErrorStatus;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

// ... (기존 imports)

@Service
@RequiredArgsConstructor
@Profile({"local", "dev"})
Expand All @@ -21,10 +29,11 @@ public class DevService {
private final GroupBuyRepository groupBuyRepository;
private final OrderRepository orderRepository;
private final OrderItemRepository orderItemRepository;
private final PaymentRepository paymentRepository; // 추가
private final DeliveryRepository deliveryRepository; // 추가

@Transactional
public void hardDeleteUser(Long userId) {
// 1. 유저가 총대로서 올린 게시글과 관련된 '타인의 주문 내역(OrderItem)' 삭제
List<GroupBuyPost> myPosts = groupBuyRepository.findAllByLeaderId(userId);

List<Long> myOptionIds = myPosts.stream()
Expand All @@ -45,4 +54,25 @@ public void hardDeleteUser(Long userId) {
// 4. 유저 삭제
userRepository.deleteById(userId);
}

// 주문 상태 강제 변경 (테스트용)
@Transactional
public void resetOrderStatus(Long orderId, OrderStatus targetStatus) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new BusinessException(ErrorStatus.ORDER_NOT_FOUND));

// 목표 상태에 따라 연관 데이터 정리
if (targetStatus == OrderStatus.WAIT_PAY) {
// WAIT_PAY로 초기화 시, 입금 정보와 운송장 정보 모두 삭제
paymentRepository.deleteByOrder_Id(orderId);
deliveryRepository.deleteByOrder_Id(orderId);
} else if (targetStatus == OrderStatus.WAIT_PAY_CHECK || targetStatus == OrderStatus.PAID) {
// WAIT_PAY_CHECK 또는 PAID로 초기화 시, 운송장 정보만 삭제 (입금 정보는 유지)
deliveryRepository.deleteByOrder_Id(orderId);
}
// SHIPPED, DELIVERED 등 그 이상 상태로 변경 시에는 삭제할 것이 없음

// 주문 상태 변경 적용
order.updateStatus(targetStatus);
}
Comment on lines +58 to +77
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Jan 23, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

git ls-files src/main/java/org/sopt/poti/ | head -30

Repository: team-poti/POTI-SERVER

Length of output: 2283


🏁 Script executed:

find src/main/java/org/sopt/poti -name "DevService.java" -o -name "*Repository.java" | grep -E "(Payment|Delivery|Order)" | head -20

Repository: team-poti/POTI-SERVER

Length of output: 455


🏁 Script executed:

cat -n src/main/java/org/sopt/poti/global/dev/DevService.java | sed -n '50,85p'

Repository: team-poti/POTI-SERVER

Length of output: 1243


🏁 Script executed:

find src/main/java/org/sopt/poti -type f -name "*.java" | xargs grep -l "deleteByOrder_Id" | head -10

Repository: team-poti/POTI-SERVER

Length of output: 275


🏁 Script executed:

find src/main/java/org/sopt/poti -type f -name "*Repository.java" | xargs grep -l "deleteByOrder" | head -10

Repository: team-poti/POTI-SERVER

Length of output: 220


🏁 Script executed:

cat -n src/main/java/org/sopt/poti/domain/payment/repository/PaymentRepository.java

Repository: team-poti/POTI-SERVER

Length of output: 465


🏁 Script executed:

cat -n src/main/java/org/sopt/poti/domain/delivery/repository/DeliveryRepository.java

Repository: team-poti/POTI-SERVER

Length of output: 761


🏁 Script executed:

find src/main/java/org/sopt/poti -type f -name "Order.java"

Repository: team-poti/POTI-SERVER

Length of output: 123


🏁 Script executed:

find src/main/java/org/sopt/poti -type f -name "Payment.java"

Repository: team-poti/POTI-SERVER

Length of output: 127


🏁 Script executed:

find src/main/java/org/sopt/poti -type f -name "Delivery.java"

Repository: team-poti/POTI-SERVER

Length of output: 129


🏁 Script executed:

cat -n src/main/java/org/sopt/poti/domain/order/entity/Order.java

Repository: team-poti/POTI-SERVER

Length of output: 5839


🏁 Script executed:

cat -n src/main/java/org/sopt/poti/domain/payment/entity/Payment.java

Repository: team-poti/POTI-SERVER

Length of output: 2547


🏁 Script executed:

cat -n src/main/java/org/sopt/poti/domain/delivery/entity/Delivery.java

Repository: team-poti/POTI-SERVER

Length of output: 1789


벌크 삭제 후 접근하지 않아 현재는 문제 없지만, 설계상 개선이 필요해.

deleteByOrder_Id는 벌크 삭제라 cascade/orphanRemoval을 무시하는데, Order가 cascade = CascadeType.ALL, orphanRemoval = true로 설정되어 있어. 지금은 삭제 후 payment/delivery를 접근하지 않아서 런타임 에러가 안 나지만, 나중에 코드가 수정되면 문제가 생길 수 있으니 cascade delete를 활용하거나 엔티티를 직접 로드해서 삭제하는 게 낫겠어.

🤖 Prompt for AI Agents
In `@src/main/java/org/sopt/poti/global/dev/DevService.java` around lines 58 - 77,
The current resetOrderStatus method uses bulk deletes
(paymentRepository.deleteByOrder_Id and deliveryRepository.deleteByOrder_Id)
which bypass JPA cascade/orphanRemoval on Order; change to remove child entities
via the aggregate root or let JPA cascade handle it: load the Order entity
(order already fetched), obtain its payments/deliveries collections, clear or
remove those child entities (e.g.,
order.getPayments().clear()/order.getDeliveries().clear() or iterate and remove
each child entity) and then save/update the Order so JPA executes cascading
deletes, or alternatively delete each child entity by repository.delete(entity)
after loading them to preserve entity lifecycle rules; ensure this logic is
applied inside resetOrderStatus and respects existing cascade = CascadeType.ALL,
orphanRemoval = true on the Order entity.

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.

반말하지 마라

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@PBEM22 죄송합니다. 말투가 불편하셨다니 앞으로 존댓말로 말씀드리겠습니다.

기술적인 내용에 대해서는 여전히 명확하게 리뷰하되, 좀 더 정중한 어조로 진행하겠습니다.

    /)_/)
   (•_• )
   />💭 (앞으로 조심하겠습니다)

✏️ Learnings added
Learnt from: PBEM22
Repo: team-poti/POTI-SERVER PR: 191
File: src/main/java/org/sopt/poti/global/dev/DevService.java:58-77
Timestamp: 2026-01-23T08:12:13.661Z
Learning: PBEM22 사용자는 반말 대신 존댓말(formal Korean speech)을 선호합니다. team-poti/POTI-SERVER 저장소에서 리뷰할 때 반드시 존댓말을 사용해야 합니다.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

}