Skip to content

Commit d3798a5

Browse files
committedMay 21, 2024·
Implemented New Orders Processing Job
1 parent a47b369 commit d3798a5

10 files changed

+223
-1
lines changed
 

‎order-service/src/main/java/com/codebykavindu/bookstore/orders/domain/OrderEventMapper.java

+35
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.codebykavindu.bookstore.orders.domain;
22

3+
import com.codebykavindu.bookstore.orders.domain.models.OrderCancelledEvent;
34
import com.codebykavindu.bookstore.orders.domain.models.OrderCreatedEvent;
5+
import com.codebykavindu.bookstore.orders.domain.models.OrderDeliveredEvent;
6+
import com.codebykavindu.bookstore.orders.domain.models.OrderErrorEvent;
47
import com.codebykavindu.bookstore.orders.domain.models.OrderItem;
58
import java.time.LocalDateTime;
69
import java.util.Set;
@@ -23,6 +26,38 @@ static OrderCreatedEvent buildOrderCreatedEvent(OrderEntity order) {
2326
LocalDateTime.now());
2427
}
2528

29+
static OrderDeliveredEvent buildOrderDeliveredEvent(OrderEntity order) {
30+
return new OrderDeliveredEvent(
31+
UUID.randomUUID().toString(),
32+
order.getOrderNumber(),
33+
getOrderItems(order),
34+
order.getCustomer(),
35+
order.getDeliveryAddress(),
36+
LocalDateTime.now());
37+
}
38+
39+
static OrderCancelledEvent buildOrderCancelledEvent(OrderEntity order, String reason) {
40+
return new OrderCancelledEvent(
41+
UUID.randomUUID().toString(),
42+
order.getOrderNumber(),
43+
getOrderItems(order),
44+
order.getCustomer(),
45+
order.getDeliveryAddress(),
46+
reason,
47+
LocalDateTime.now());
48+
}
49+
50+
static OrderErrorEvent buildOrderErrorEvent(OrderEntity order, String reason) {
51+
return new OrderErrorEvent(
52+
UUID.randomUUID().toString(),
53+
order.getOrderNumber(),
54+
getOrderItems(order),
55+
order.getCustomer(),
56+
order.getDeliveryAddress(),
57+
reason,
58+
LocalDateTime.now());
59+
}
60+
2661
private static Set<OrderItem> getOrderItems(OrderEntity order) {
2762
return order.getItems().stream()
2863
.map(item -> new OrderItem(item.getCode(), item.getName(), item.getPrice(), item.getQuantity()))

‎order-service/src/main/java/com/codebykavindu/bookstore/orders/domain/OrderEventPublisher.java

+15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.codebykavindu.bookstore.orders.domain;
22

33
import com.codebykavindu.bookstore.orders.ApplicationProperties;
4+
import com.codebykavindu.bookstore.orders.domain.models.OrderCancelledEvent;
45
import com.codebykavindu.bookstore.orders.domain.models.OrderCreatedEvent;
6+
import com.codebykavindu.bookstore.orders.domain.models.OrderDeliveredEvent;
7+
import com.codebykavindu.bookstore.orders.domain.models.OrderErrorEvent;
58
import org.springframework.amqp.rabbit.core.RabbitTemplate;
69
import org.springframework.stereotype.Component;
710

@@ -23,6 +26,18 @@ public void publish(OrderCreatedEvent event) {
2326
this.send(properties.newOrdersQueue(), event);
2427
}
2528

29+
public void publish(OrderDeliveredEvent event) {
30+
this.send(properties.deliveredOrdersQueue(), event);
31+
}
32+
33+
public void publish(OrderCancelledEvent event) {
34+
this.send(properties.cancelledOrdersQueue(), event);
35+
}
36+
37+
public void publish(OrderErrorEvent event) {
38+
this.send(properties.errorOrdersQueue(), event);
39+
}
40+
2641
private void send(String routingKey, Object payload) {
2742
rabbitTemplate.convertAndSend(properties.orderEventsExchange(), routingKey, payload);
2843
}

‎order-service/src/main/java/com/codebykavindu/bookstore/orders/domain/OrderEventService.java

+47
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.codebykavindu.bookstore.orders.domain;
22

3+
import com.codebykavindu.bookstore.orders.domain.models.OrderCancelledEvent;
34
import com.codebykavindu.bookstore.orders.domain.models.OrderCreatedEvent;
5+
import com.codebykavindu.bookstore.orders.domain.models.OrderDeliveredEvent;
6+
import com.codebykavindu.bookstore.orders.domain.models.OrderErrorEvent;
47
import com.codebykavindu.bookstore.orders.domain.models.OrderEventType;
58
import com.fasterxml.jackson.core.JsonProcessingException;
69
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -42,6 +45,36 @@ void save(OrderCreatedEvent event) {
4245
this.orderEventRepository.save(orderEvent);
4346
}
4447

48+
void save(OrderDeliveredEvent event) {
49+
OrderEventEntity orderEvent = new OrderEventEntity();
50+
orderEvent.setEventId(event.eventId());
51+
orderEvent.setEventType(OrderEventType.ORDER_DELIVERED);
52+
orderEvent.setOrderNumber(event.orderNumber());
53+
orderEvent.setCreatedAt(event.createdAt());
54+
orderEvent.setPayload(toJsonPayload(event));
55+
this.orderEventRepository.save(orderEvent);
56+
}
57+
58+
void save(OrderCancelledEvent event) {
59+
OrderEventEntity orderEvent = new OrderEventEntity();
60+
orderEvent.setEventId(event.eventId());
61+
orderEvent.setEventType(OrderEventType.ORDER_CANCELLED);
62+
orderEvent.setOrderNumber(event.orderNumber());
63+
orderEvent.setCreatedAt(event.createdAt());
64+
orderEvent.setPayload(toJsonPayload(event));
65+
this.orderEventRepository.save(orderEvent);
66+
}
67+
68+
void save(OrderErrorEvent event) {
69+
OrderEventEntity orderEvent = new OrderEventEntity();
70+
orderEvent.setEventId(event.eventId());
71+
orderEvent.setEventType(OrderEventType.ORDER_PROCESSING_FAILED);
72+
orderEvent.setOrderNumber(event.orderNumber());
73+
orderEvent.setCreatedAt(event.createdAt());
74+
orderEvent.setPayload(toJsonPayload(event));
75+
this.orderEventRepository.save(orderEvent);
76+
}
77+
4578
public void publishOrderEvents() {
4679
Sort sort = Sort.by("createdAt").ascending();
4780
List<OrderEventEntity> events = orderEventRepository.findAll(sort);
@@ -59,6 +92,20 @@ private void publishEvent(OrderEventEntity event) {
5992
OrderCreatedEvent orderCreatedEvent = fromJsonPayload(event.getPayload(), OrderCreatedEvent.class);
6093
orderEventPublisher.publish(orderCreatedEvent);
6194
break;
95+
case ORDER_DELIVERED:
96+
OrderDeliveredEvent orderDeliveredEvent =
97+
fromJsonPayload(event.getPayload(), OrderDeliveredEvent.class);
98+
orderEventPublisher.publish(orderDeliveredEvent);
99+
break;
100+
case ORDER_CANCELLED:
101+
OrderCancelledEvent orderCancelledEvent =
102+
fromJsonPayload(event.getPayload(), OrderCancelledEvent.class);
103+
orderEventPublisher.publish(orderCancelledEvent);
104+
break;
105+
case ORDER_PROCESSING_FAILED:
106+
OrderErrorEvent orderErrorEvent = fromJsonPayload(event.getPayload(), OrderErrorEvent.class);
107+
orderEventPublisher.publish(orderErrorEvent);
108+
break;
62109
default:
63110
log.warn("Unknown Event Type: {}", eventType);
64111
}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
package com.codebykavindu.bookstore.orders.domain;
22

3+
import com.codebykavindu.bookstore.orders.domain.models.OrderStatus;
4+
import java.util.List;
5+
import java.util.Optional;
36
import org.springframework.data.jpa.repository.JpaRepository;
47

58
/**
69
* @author Kavindu Perera
710
*/
8-
interface OrderRepository extends JpaRepository<OrderEntity, Long> {}
11+
interface OrderRepository extends JpaRepository<OrderEntity, Long> {
12+
List<OrderEntity> findByStatus(OrderStatus status);
13+
14+
Optional<OrderEntity> findByOrderNumber(String orderNumber);
15+
16+
default void updateOrderStatus(String orderNumber, OrderStatus status) {
17+
OrderEntity order = this.findByOrderNumber(orderNumber).orElseThrow();
18+
order.setStatus(status);
19+
this.save(order);
20+
}
21+
}

‎order-service/src/main/java/com/codebykavindu/bookstore/orders/domain/OrderService.java

+36
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import com.codebykavindu.bookstore.orders.domain.models.CreateOrderRequest;
44
import com.codebykavindu.bookstore.orders.domain.models.CreateOrderResponse;
55
import com.codebykavindu.bookstore.orders.domain.models.OrderCreatedEvent;
6+
import com.codebykavindu.bookstore.orders.domain.models.OrderStatus;
7+
import java.util.List;
68
import org.slf4j.Logger;
79
import org.slf4j.LoggerFactory;
810
import org.springframework.stereotype.Service;
@@ -15,6 +17,7 @@
1517
@Transactional
1618
public class OrderService {
1719
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
20+
private static final List<String> DELIVERY_ALLOWED_COUNTRIES = List.of("INDIA", "USA", "GERMANY", "UK");
1821

1922
private final OrderRepository orderRepository;
2023
private final OrderValidator orderValidator;
@@ -36,4 +39,37 @@ public CreateOrderResponse createOrder(String userName, CreateOrderRequest reque
3639
orderEventService.save(orderCreatedEvent);
3740
return new CreateOrderResponse(savedOrder.getOrderNumber());
3841
}
42+
43+
public void processNewOrders() {
44+
List<OrderEntity> orders = orderRepository.findByStatus(OrderStatus.NEW);
45+
log.info("Found {} new orders to process", orders.size());
46+
for (OrderEntity order : orders) {
47+
this.process(order);
48+
}
49+
}
50+
51+
private void process(OrderEntity order) {
52+
try {
53+
if (canBeDelivered(order)) {
54+
log.info("OrderNumber: {} can be delivered", order.getOrderNumber());
55+
orderRepository.updateOrderStatus(order.getOrderNumber(), OrderStatus.DELIVERED);
56+
orderEventService.save(OrderEventMapper.buildOrderDeliveredEvent(order));
57+
58+
} else {
59+
log.info("OrderNumber: {} can not be delivered", order.getOrderNumber());
60+
orderRepository.updateOrderStatus(order.getOrderNumber(), OrderStatus.CANCELLED);
61+
orderEventService.save(
62+
OrderEventMapper.buildOrderCancelledEvent(order, "Can't deliver to the location"));
63+
}
64+
} catch (RuntimeException e) {
65+
log.error("Failed to process Order with orderNumber: {}", order.getOrderNumber(), e);
66+
orderRepository.updateOrderStatus(order.getOrderNumber(), OrderStatus.ERROR);
67+
orderEventService.save(OrderEventMapper.buildOrderErrorEvent(order, e.getMessage()));
68+
}
69+
}
70+
71+
private boolean canBeDelivered(OrderEntity order) {
72+
return DELIVERY_ALLOWED_COUNTRIES.contains(
73+
order.getDeliveryAddress().country().toUpperCase());
74+
}
3975
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.codebykavindu.bookstore.orders.domain.models;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.Set;
5+
6+
/**
7+
* @author Kavindu Perera
8+
*/
9+
public record OrderCancelledEvent(
10+
String eventId,
11+
String orderNumber,
12+
Set<OrderItem> items,
13+
Customer customer,
14+
Address deliveryAddress,
15+
String reason,
16+
LocalDateTime createdAt) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.codebykavindu.bookstore.orders.domain.models;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.Set;
5+
6+
/**
7+
* @author Kavindu Perera
8+
*/
9+
public record OrderDeliveredEvent(
10+
String eventId,
11+
String orderNumber,
12+
Set<OrderItem> items,
13+
Customer customer,
14+
Address deliveryAddress,
15+
LocalDateTime createdAt) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.codebykavindu.bookstore.orders.domain.models;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.Set;
5+
6+
/**
7+
* @author Kavindu Perera
8+
*/
9+
public record OrderErrorEvent(
10+
String eventId,
11+
String orderNumber,
12+
Set<OrderItem> items,
13+
Customer customer,
14+
Address deliveryAddress,
15+
String reason,
16+
LocalDateTime createdAt) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.codebykavindu.bookstore.orders.jobs;
2+
3+
import com.codebykavindu.bookstore.orders.domain.OrderService;
4+
import java.time.Instant;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import org.springframework.scheduling.annotation.Scheduled;
8+
import org.springframework.stereotype.Component;
9+
10+
/**
11+
* @author Kavindu Perera
12+
*/
13+
@Component
14+
class OrderProcessingJob {
15+
private static final Logger log = LoggerFactory.getLogger(OrderProcessingJob.class);
16+
17+
private final OrderService orderService;
18+
19+
OrderProcessingJob(OrderService orderService) {
20+
this.orderService = orderService;
21+
}
22+
23+
@Scheduled(cron = "${orders.new-orders-job-cron}")
24+
public void processNewOrders() {
25+
log.info("Processing new orders at {}", Instant.now());
26+
orderService.processNewOrders();
27+
}
28+
}

‎order-service/src/main/resources/application.properties

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ orders.cancelled-orders-queue=cancelled-orders
1313
orders.error-orders-queue=error-orders
1414

1515
orders.publish-order-events-job-cron=0/5 * * * * *
16+
orders.new-orders-job-cron=0/10 * * * * *
1617

1718
# Database Configurations
1819
spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:25432/postgres}

0 commit comments

Comments
 (0)
Please sign in to comment.