Skip to content

Commit aeda897

Browse files
committed
[250608] 배송기능 - enum 상태값별 이벤트 처리, 프로토콜버퍼 적용, 업데이트 로직 추가개발
1 parent 9dad03f commit aeda897

19 files changed

+263
-375
lines changed

src/main/java/com/ecommerce/delivery/dto/request/DeliveryRequest.java

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/java/com/ecommerce/delivery/dto/response/DeliveryResponse.java

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/java/com/ecommerce/delivery/repository/DeliveryRepository.java

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,71 @@
11
package com.ecommerce.shipment.domain;
22

3+
4+
import com.ecommerce.shipment.event.producer.ShipmentEventPublisher;
5+
import lombok.extern.slf4j.Slf4j;
6+
7+
import java.util.function.BiConsumer;
8+
9+
@Slf4j
310
public enum ExternalShippingStatus {
4-
READY,
5-
READY_FOR_PICKUP,
6-
SHIPPING,
7-
DELIVERED,
8-
FAILED,
9-
CANCELLED;
11+
12+
13+
READY((shipment, publisher) -> publisher.publishShipStatusChanged(shipment)),
14+
15+
READY_FOR_PICKUP((shipment, publisher) -> publisher.publishShipStatusChanged(shipment)),
16+
17+
SHIPPING((shipment, publisher) -> publisher.publishShipStatusChanged(shipment)),
18+
19+
DELIVERED((shipment, publisher) -> publisher.publishShipCompleted(shipment)),
20+
21+
FAILED((shipment, publisher) -> publisher.publishShipFailed(shipment)),
22+
23+
CANCELLED((shipment, publisher) -> publisher.publishShipCompleted(shipment));
24+
25+
// 함수형 인터페이스 - 각 배송 상태별 처리 로직
26+
private final BiConsumer<Shipment, ShipmentEventPublisher> processor;
27+
28+
ExternalShippingStatus(BiConsumer<Shipment, ShipmentEventPublisher> processor) {
29+
this.processor = processor;
30+
}
31+
32+
// 상태별 비즈니스 로직 실행
33+
public void process(Shipment shipment, ShipmentEventPublisher publisher) {
34+
this.processor.accept(shipment, publisher);
35+
}
36+
37+
38+
// 카프카 발행용 String 변환 - DELIVERED, FAILED 등 문자열 그대로 사용
39+
public String toKafkaString() {
40+
return this.name();
41+
}
42+
43+
// 카프카에서 받은 String을 Enum으로 변환
44+
public static ExternalShippingStatus fromKafkaString(String status) {
45+
try {
46+
return ExternalShippingStatus.valueOf(status.trim().toUpperCase());
47+
} catch (IllegalArgumentException e) {
48+
throw new IllegalArgumentException("Unknown shipping status: " + status, e);
49+
}
50+
}
51+
52+
/**
53+
* 상태 전환 가능 여부 (비즈니스 규칙)
54+
*/
55+
public boolean canTransitionTo(ExternalShippingStatus newStatus) {
56+
return switch (this) {
57+
case READY -> newStatus == READY_FOR_PICKUP || newStatus == CANCELLED;
58+
case READY_FOR_PICKUP -> newStatus == SHIPPING || newStatus == CANCELLED;
59+
case SHIPPING -> newStatus == DELIVERED || newStatus == FAILED;
60+
case DELIVERED, FAILED, CANCELLED -> false; // 최종 상태
61+
};
62+
}
63+
64+
/**
65+
* 최종 상태 여부
66+
*/
67+
public boolean isFinalStatus() {
68+
return this == DELIVERED || this == FAILED || this == CANCELLED;
69+
}
70+
1071
}

src/main/java/com/ecommerce/shipment/domain/Shipment.java

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ecommerce.shipment.domain;
22

3+
import com.ecommerce.shipment.event.producer.ShipmentEventPublisher;
34
import jakarta.persistence.*;
45
import lombok.AllArgsConstructor;
56
import lombok.Builder;
@@ -57,54 +58,32 @@ protected void onUpdate() {
5758
updtDt = LocalDateTime.now();
5859
}
5960

60-
// 택배사 정보 업데이트
61+
// 택배사 정보 업데이트 - JPA Dirty Checking 활용
6162
public void updateCarrierDetailInfo(String carrierName, String trackingNumber) {
62-
Shipment.builder()
63-
.id(id)
64-
.orderUUID(orderUUID)
65-
.shipUUID(shipUUID)
66-
.carrierName(carrierName)
67-
.trackingNumber(trackingNumber)
68-
.status(status)
69-
.estmtDeliverDt(estmtDeliverDt)
70-
.creaDt(creaDt)
71-
.build();
63+
this.carrierName = carrierName;
64+
this.trackingNumber = trackingNumber;
65+
// @PreUpdate에 의해 updtDt 자동 갱신
7266
}
7367

74-
// 상태 업데이트 메서드 (불변성 유지)
75-
public Shipment updateShippingStatus(ExternalShippingStatus newStatus) {
76-
return Shipment.builder()
77-
.id(id)
78-
.orderUUID(orderUUID)
79-
.shipUUID(shipUUID)
80-
.carrierName(carrierName)
81-
.trackingNumber(trackingNumber)
82-
.status(newStatus)
83-
.estmtDeliverDt(estmtDeliverDt)
84-
.creaDt(creaDt)
85-
.build();
68+
// 상태 업데이트 메서드 - JPA Dirty Checking 활용
69+
public void updateShippingStatus(ExternalShippingStatus newStatus) {
70+
// 1. 비즈니스 규칙 검증
71+
if (!status.canTransitionTo(newStatus)) {
72+
throw new IllegalStateException(String.format("Cannot transition from %s to %s", status, newStatus));
73+
}
74+
75+
// 2. 상태 변경 (Dirty Checking 으로 자동 UPDATE)
76+
this.status = newStatus;
77+
// 3. @PreUpdate에 의해 updtDt 자동 갱신
8678
}
8779

8880
public boolean hasStatusDelivered() {
8981
return status.equals(ExternalShippingStatus.DELIVERED);
9082
}
9183

92-
public boolean hasStatusFailed() {
93-
return status.equals(ExternalShippingStatus.FAILED);
94-
}
95-
96-
97-
public boolean hasDeliveryDetailInfo() {
98-
return hasCarrierName() && hasTrackingNumber();
99-
}
100-
101-
public boolean hasCarrierName() {
102-
return carrierName != null;
103-
}
104-
105-
106-
public boolean hasTrackingNumber() {
107-
return trackingNumber != null;
84+
// 비즈니스 로직 처리 (함수형 enum 활용)
85+
public void processStatusChange(ShipmentEventPublisher publisher) {
86+
status.process(this, publisher);
10887
}
10988

11089
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.ecommerce.shipment.dto.request;
2+
3+
import com.ecommerce.shipment.domain.ExternalShippingStatus;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
7+
@Getter
8+
@Builder
9+
public class CarrierUpdateRequest {
10+
11+
private final String carrierName;
12+
private final String trackingNumber;
13+
private final ExternalShippingStatus newStatus;
14+
15+
public static CarrierUpdateRequest of(String carrierName, String trackingNumber, ExternalShippingStatus status) {
16+
return CarrierUpdateRequest.builder()
17+
.carrierName(carrierName)
18+
.trackingNumber(trackingNumber)
19+
.newStatus(status)
20+
.build();
21+
}
22+
23+
}

src/main/java/com/ecommerce/shipment/dto/request/ShipmentRequest.java

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/java/com/ecommerce/shipment/dto/response/ShipmentResponse.java

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.ecommerce.shipment.event.consumer;
22

3-
import com.ecommerce.proto.EdaMessage;
3+
import com.ecommerce.shipment.domain.OrderLifecycleMessage;
4+
import com.ecommerce.shipment.domain.Shipment;
45
import com.ecommerce.shipment.service.ShipmentService;
56
import com.google.protobuf.InvalidProtocolBufferException;
67
import lombok.RequiredArgsConstructor;
@@ -9,7 +10,6 @@
910
import org.springframework.kafka.annotation.KafkaListener;
1011
import org.springframework.stereotype.Service;
1112

12-
import java.util.List;
1313
import java.util.UUID;
1414

1515
@Slf4j
@@ -19,7 +19,6 @@ public class ShipmentEventConsumer {
1919

2020
private final ShipmentService shipmentService;
2121

22-
2322
@KafkaListener(topics = "shipment-events", groupId = "shipment-service")
2423
public void consumeShipmentEvents(ConsumerRecord<String, byte[]> record) {
2524
try {
@@ -39,30 +38,32 @@ public void consumeShipmentEvents(ConsumerRecord<String, byte[]> record) {
3938

4039
private void operateOrderSucceed(byte[] eventBytes) {
4140
try {
42-
EdaMessage.OrderCreatedEvent event = EdaMessage.OrderCreatedEvent.parseFrom(eventBytes);
43-
UUID orderUUID = UUID.fromString(event.getOrderUUID());
44-
shipmentService.getShipListByOrderUUID(List.of(orderUUID));
45-
} catch (InvalidProtocolBufferException e) {
46-
log.error("[shipment-operate] : ProtoBuf parse error : {}", e.getMessage());
41+
UUID orderUUID = parseOrderUUID(eventBytes);
42+
Shipment succeedOrder = shipmentService.getShipmentByOrderUUID(orderUUID);
43+
shipmentService.createExecuteShipment(succeedOrder);
4744
} catch (Exception e) {
4845
log.error("[shipment-operate] : created Order error : {}", e.getMessage());
4946
}
50-
51-
5247
}
5348

5449
private void operateOrderCancelled(byte[] eventBytes) {
5550
try {
56-
EdaMessage.OrderCreatedEvent event = EdaMessage.OrderCreatedEvent.parseFrom(eventBytes);
57-
UUID orderUUID = UUID.fromString(event.getOrderUUID());
58-
// shipmentService
59-
} catch (InvalidProtocolBufferException e) {
60-
log.error("ProtoBuf parse error : {}", e.getMessage());
51+
UUID orderUUID = parseOrderUUID(eventBytes);
52+
Shipment updatedShip = shipmentService.getShipmentByOrderUUID(orderUUID);
53+
shipmentService.cancelShipment(updatedShip);
6154
} catch (Exception e) {
6255
log.error("Canceled Order error : {}", e.getMessage());
6356
}
57+
}
6458

65-
59+
private UUID parseOrderUUID(byte[] eventBytes) {
60+
try {
61+
OrderLifecycleMessage.OrderLifecycleEvent orderEvent = OrderLifecycleMessage.OrderLifecycleEvent.parseFrom(eventBytes);
62+
return UUID.fromString(orderEvent.getOrderUuid());
63+
} catch (InvalidProtocolBufferException e) {
64+
log.error("ProtoBuf parse error : {}", e.getMessage());
65+
throw new RuntimeException("Failed to parse order UUID", e);
66+
}
6667
}
6768

6869
}

src/main/java/com/ecommerce/shipment/event/model/ShipmentCompletedEvent.java

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/main/java/com/ecommerce/shipment/event/model/ShipmentCreatedEvent.java

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/main/java/com/ecommerce/shipment/event/model/ShipmentFailedEvent.java

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)