Skip to content

Commit af5cb9e

Browse files
committed
✨ feat: 주문 배송 시작 스케줄링 및 상태 업데이트 로직 추가
1 parent 28d9da6 commit af5cb9e

File tree

5 files changed

+79
-1
lines changed

5 files changed

+79
-1
lines changed

src/main/java/com/jajaja/domain/order/entity/OrderProduct.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,8 @@ public class OrderProduct extends BaseEntity {
4343
@ManyToOne(fetch = FetchType.LAZY)
4444
@JoinColumn(name = "option_id")
4545
private ProductOption productOption;
46+
47+
public void updateStatus(OrderStatus status) {
48+
this.status = status;
49+
}
4650
}

src/main/java/com/jajaja/domain/order/service/OrderCommandService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ public interface OrderCommandService {
1111
OrderPrepareResponseDto prepareOrder(Long memberId, OrderPrepareRequestDto request);
1212
OrderApproveResponseDto approveOrder(Long memberId, OrderApproveRequestDto request);
1313
OrderRefundResponseDto refundOrder(Long memberId, OrderRefundRequestDto request);
14+
void startShipping(Long orderId);
1415
}

src/main/java/com/jajaja/domain/order/service/OrderCommandServiceImpl.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.http.HttpHeaders;
4545
import org.springframework.http.MediaType;
4646
import org.springframework.http.ResponseEntity;
47+
import org.springframework.scheduling.annotation.Async;
4748
import org.springframework.stereotype.Service;
4849
import org.springframework.transaction.annotation.Transactional;
4950
import org.springframework.web.client.HttpClientErrorException;
@@ -204,6 +205,9 @@ public OrderApproveResponseDto approveOrder(Long memberId, OrderApproveRequestDt
204205
// 최초 구매 시 포인트 지급
205206
pointCommandService.addFirstPurchasePointsIfPossible(member);
206207

208+
// 30초 후 배송 시작 스케줄링
209+
scheduleShippingStart(order.getId());
210+
207211
return OrderApproveResponseDto.of(order);
208212

209213
} catch (HttpClientErrorException e) { // 400번대 에러
@@ -215,6 +219,9 @@ public OrderApproveResponseDto approveOrder(Long memberId, OrderApproveRequestDt
215219
} catch (Exception e) {
216220
log.error("[OrderCommandService] 주문 생성 실패 - 회원ID: {}, 에러: {}", memberId, e.getMessage(), e);
217221
order.updateStatus(OrderStatus.ABORTED);
222+
// OrderProduct도 함께 취소 상태로 변경
223+
order.getOrderProducts().forEach(orderProduct ->
224+
orderProduct.updateStatus(OrderStatus.ABORTED));
218225
throw new GeneralException(ErrorStatus._INTERNAL_SERVER_ERROR);
219226
}
220227
}
@@ -308,6 +315,9 @@ public OrderRefundResponseDto refundOrder(Long memberId, OrderRefundRequestDto r
308315
}
309316

310317
order.updateStatus(OrderStatus.REFUNDED);
318+
// OrderProduct도 함께 환불 상태로 변경
319+
order.getOrderProducts().forEach(orderProduct ->
320+
orderProduct.updateStatus(OrderStatus.REFUNDED));
311321

312322
// 환불 성공 시 구매 통계에서 판매 개수만큼 수량 줄이기
313323
order.getOrderProducts()
@@ -333,6 +343,9 @@ public OrderRefundResponseDto refundOrder(Long memberId, OrderRefundRequestDto r
333343
throw new TossPaymentException(ErrorStatus.TOSS_PAYMENT_SERVER_ERROR);
334344
} catch (Exception e) {
335345
order.updateStatus(OrderStatus.REFUND_FAILED);
346+
// OrderProduct도 함께 환불 실패 상태로 변경
347+
order.getOrderProducts().forEach(orderProduct ->
348+
orderProduct.updateStatus(OrderStatus.REFUND_FAILED));
336349
log.error("[OrderCommandService] 환불 처리 실패 - 주문ID: {}, 에러: {}", request.orderId(), e.getMessage(), e);
337350
throw new GeneralException(ErrorStatus.REFUND_FAILED);
338351
}
@@ -443,4 +456,38 @@ private HttpHeaders getHeaders() {
443456

444457
return headers;
445458
}
459+
460+
@Async("orderTaskExecutor")
461+
protected void scheduleShippingStart(Long orderId) {
462+
try {
463+
Thread.sleep(30000); // 30초 대기
464+
startShipping(orderId);
465+
} catch (InterruptedException e) {
466+
log.error("[OrderCommandService] 배송 시작 스케줄링 중단 - 주문ID: {}", orderId, e);
467+
Thread.currentThread().interrupt();
468+
} catch (Exception e) {
469+
log.error("[OrderCommandService] 배송 시작 스케줄링 실패 - 주문ID: {}", orderId, e);
470+
}
471+
}
472+
473+
@Override
474+
@Transactional
475+
public void startShipping(Long orderId) {
476+
try {
477+
Order order = orderRepository.findById(orderId)
478+
.orElseThrow(() -> new BadRequestException(ErrorStatus.ORDER_NOT_FOUND));
479+
480+
if (order.getOrderStatus() == OrderStatus.DONE) {
481+
order.updateStatus(OrderStatus.SHIPPING);
482+
// OrderProduct들도 함께 배송 상태로 변경
483+
order.getOrderProducts().forEach(orderProduct ->
484+
orderProduct.updateStatus(OrderStatus.SHIPPING));
485+
log.info("[OrderCommandService] 배송 시작 - 주문ID: {}", orderId);
486+
} else {
487+
log.warn("[OrderCommandService] 배송 시작 불가 - 주문ID: {}, 현재상태: {}", orderId, order.getOrderStatus());
488+
}
489+
} catch (Exception e) {
490+
log.error("[OrderCommandService] 배송 시작 실패 - 주문ID: {}", orderId, e);
491+
}
492+
}
446493
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.jajaja.global.config;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.scheduling.annotation.EnableAsync;
6+
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
7+
8+
import java.util.concurrent.Executor;
9+
10+
@Configuration
11+
@EnableAsync
12+
public class AsyncConfig {
13+
14+
@Bean(name = "orderTaskExecutor")
15+
public Executor orderTaskExecutor() {
16+
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
17+
executor.setCorePoolSize(2);
18+
executor.setMaxPoolSize(5);
19+
executor.setQueueCapacity(10);
20+
executor.setThreadNamePrefix("Order-Async-");
21+
executor.initialize();
22+
return executor;
23+
}
24+
}

src/main/java/com/jajaja/global/scheduler/TeamExpireScheduler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import com.jajaja.domain.notification.service.NotificationService;
88
import com.jajaja.domain.order.entity.Order;
99
import com.jajaja.domain.order.entity.enums.OrderStatus;
10-
import com.jajaja.domain.order.repository.OrderRepository;
1110
import com.jajaja.domain.order.service.OrderCommandService;
1211
import com.jajaja.domain.order.dto.request.OrderRefundRequestDto;
1312
import com.jajaja.domain.product.entity.Product;
@@ -74,6 +73,9 @@ public void expireTeams() {
7473
if (order != null) {
7574
try {
7675
order.updateStatus(OrderStatus.TEAM_MATCHING_FAILED);
76+
// OrderProduct도 함께 팀 매칭 실패 상태로 변경
77+
order.getOrderProducts().forEach(orderProduct ->
78+
orderProduct.updateStatus(OrderStatus.TEAM_MATCHING_FAILED));
7779
OrderRefundRequestDto refundRequest = OrderRefundRequestDto.of(order.getId(), order.getPaymentKey(),"팀 매칭 실패로 인한 자동 환불");
7880
orderCommandService.refundOrder(leader.getId(), refundRequest);
7981
log.info("팀 매칭 실패 주문 자동 환불 완료 - 주문ID: {}", order.getId());

0 commit comments

Comments
 (0)