@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem;
|
package com.food.order.system;
|
||||||
|
|
||||||
public class DomainConstants {
|
public class DomainConstants {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.entity;
|
package com.food.order.system.entity;
|
||||||
|
|
||||||
|
|
||||||
public abstract class AggregateRoot<ID> extends BaseEntity<ID> {
|
public abstract class AggregateRoot<ID> extends BaseEntity<ID> {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.entity;
|
package com.food.order.system.entity;
|
||||||
|
|
||||||
public abstract class BaseEntity<ID> {
|
public abstract class BaseEntity<ID> {
|
||||||
private ID id;
|
private ID id;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.event;
|
package com.food.order.system.event;
|
||||||
|
|
||||||
|
|
||||||
// Base Domain Event Generic Class
|
// Base Domain Event Generic Class
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.sysyem.event.publisher;
|
package com.food.order.system.event.publisher;
|
||||||
|
|
||||||
import com.food.order.sysyem.event.DomainEvent;
|
import com.food.order.system.event.DomainEvent;
|
||||||
|
|
||||||
public interface DomainEventPublisher <T extends DomainEvent> {
|
public interface DomainEventPublisher <T extends DomainEvent> {
|
||||||
void publish(T event);
|
void publish(T event);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.exception;
|
package com.food.order.system.exception;
|
||||||
|
|
||||||
public class DomainException extends RuntimeException {
|
public class DomainException extends RuntimeException {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
public abstract class BaseId<T> {
|
public abstract class BaseId<T> {
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
public enum OrderApprovalStatus {
|
public enum OrderApprovalStatus {
|
||||||
APPROVED,
|
APPROVED,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
public enum OrderStatus {
|
public enum OrderStatus {
|
||||||
PENDING,
|
PENDING,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
public enum PaymentOrderStatus {
|
public enum PaymentOrderStatus {
|
||||||
PENDING,
|
PENDING,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
public enum PaymentStatus {
|
public enum PaymentStatus {
|
||||||
COMPLETED,CANCELED,FAILED
|
COMPLETED,CANCELED,FAILED
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.valueobject;
|
package com.food.order.system.valueobject;
|
||||||
|
|
||||||
public enum RestaurantOrderStatus {
|
public enum RestaurantOrderStatus {
|
||||||
PAID
|
PAID
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.food.order.sysyem.event;
|
|
||||||
|
|
||||||
public final class EmptyEvent implements DomainEvent<Void> {
|
|
||||||
|
|
||||||
public static final EmptyEvent INSTANCE = new EmptyEvent();
|
|
||||||
|
|
||||||
private EmptyEvent() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fire() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -41,6 +41,10 @@
|
|||||||
<groupId>io.confluent</groupId>
|
<groupId>io.confluent</groupId>
|
||||||
<artifactId>kafka-avro-serializer</artifactId>
|
<artifactId>kafka-avro-serializer</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.food.order</groupId>
|
||||||
|
<artifactId>outbox</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -1,34 +1,59 @@
|
|||||||
package com.food.order.system.kafka.producer;
|
package com.food.order.system.kafka.producer;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.kafka.clients.producer.RecordMetadata;
|
import org.apache.kafka.clients.producer.RecordMetadata;
|
||||||
import org.springframework.kafka.support.SendResult;
|
import org.springframework.kafka.support.SendResult;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class KafkaMessageHelper {
|
public class KafkaMessageHelper {
|
||||||
|
|
||||||
public <T> ListenableFutureCallback<SendResult<String, T>> getKafkaCallBack
|
private final ObjectMapper objectMapper;
|
||||||
(String responseTopicName, T t,String orderId, String requestAvroModelName) {
|
|
||||||
return new ListenableFutureCallback<>() {
|
|
||||||
|
public <T, U> ListenableFutureCallback<SendResult<String, T>>
|
||||||
|
getKafkaCallback(String responseTopicName, T avroModel, U outboxMessage,
|
||||||
|
BiConsumer<U, OutboxStatus> outboxCallback,
|
||||||
|
String orderId, String avroModelName) {
|
||||||
|
return new ListenableFutureCallback<SendResult<String, T>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Throwable ex) {
|
public void onFailure(Throwable ex) {
|
||||||
log.error("Error while sending " + requestAvroModelName +
|
log.error("Error while sending {} with message: {} and outbox type: {} to topic {}",
|
||||||
" to " + responseTopicName + " for orderId " + orderId, ex);
|
avroModelName, avroModel.toString(), outboxMessage.getClass().getName(), responseTopicName, ex);
|
||||||
|
outboxCallback.accept(outboxMessage, OutboxStatus.FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(SendResult<String, T> result) {
|
public void onSuccess(SendResult<String, T> result) {
|
||||||
RecordMetadata recordMetadata = result.getRecordMetadata();
|
RecordMetadata metadata = result.getRecordMetadata();
|
||||||
log.info("Received successful response from kafka for order id : {} Topic : {} Partition : {} , Offset : {} , Timestamp : {}",
|
log.info("Received successful response from Kafka for order id: {}" +
|
||||||
|
" Topic: {} Partition: {} Offset: {} Timestamp: {}",
|
||||||
orderId,
|
orderId,
|
||||||
recordMetadata.topic(),
|
metadata.topic(),
|
||||||
recordMetadata.partition(),
|
metadata.partition(),
|
||||||
recordMetadata.offset(),
|
metadata.offset(),
|
||||||
recordMetadata.timestamp());
|
metadata.timestamp());
|
||||||
|
outboxCallback.accept(outboxMessage, OutboxStatus.COMPLETED);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> T getOrderEventPayload(String payload, Class<T> outputType) {
|
||||||
|
try {
|
||||||
|
return objectMapper.readValue(payload, outputType);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("Could not read {} object!", outputType.getName(), e);
|
||||||
|
throw new OrderDomainException("Could not read " + outputType.getName() + " object!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.food.order.system.service.app.api;
|
package com.food.order.system.service.app.api;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderCommand;
|
import com.food.order.system.dto.create.CreateOrderCommand;
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderResponse;
|
import com.food.order.system.dto.create.CreateOrderResponse;
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderQuery;
|
import com.food.order.system.dto.track.TrackOrderQuery;
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderResponse;
|
import com.food.order.system.dto.track.TrackOrderResponse;
|
||||||
import com.food.order.sysyem.ports.input.service.OrderApplicationService;
|
import com.food.order.system.ports.input.service.OrderApplicationService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
|||||||
@@ -36,6 +36,11 @@
|
|||||||
<artifactId>order-messaging</artifactId>
|
<artifactId>order-messaging</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.system.order.domain;
|
package com.food.order.system;
|
||||||
|
|
||||||
import com.food.order.system.domain.service.OrderDomainService;
|
import com.food.order.system.domain.service.OrderDomainService;
|
||||||
import com.food.order.system.domain.service.impl.OrderDomainServiceImpl;
|
import com.food.order.system.domain.service.impl.OrderDomainServiceImpl;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.system.order.domain;
|
package com.food.order.system;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package com.food.order.system;
|
||||||
|
|
||||||
|
|
||||||
|
import com.food.order.system.data.access.outbox.payment.entity.PaymentOutboxEntity;
|
||||||
|
import com.food.order.system.data.access.outbox.payment.repository.PaymentOutboxJpaRepository;
|
||||||
|
import com.food.order.system.dto.message.PaymentResponse;
|
||||||
|
import com.food.order.system.saga.OrderPaymentSaga;
|
||||||
|
import com.food.order.system.saga.SagaStatus;
|
||||||
|
import com.food.order.system.valueobject.PaymentStatus;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.dao.OptimisticLockingFailureException;
|
||||||
|
import org.springframework.test.context.jdbc.Sql;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
import static com.food.order.system.outbox.order.SagaConst.ORDER_PROCESSING_SAGA;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@SpringBootTest(classes = OrderServiceApplication.class)
|
||||||
|
@Sql(value = {"classpath:sql/OrderPaymentSagaTestSetUp.sql"})
|
||||||
|
@Sql(value = {"classpath:sql/OrderPaymentSagaTestCleanUp.sql"}, executionPhase = AFTER_TEST_METHOD)
|
||||||
|
class OrderPaymentSagaTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderPaymentSaga orderPaymentSaga;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PaymentOutboxJpaRepository paymentOutboxJpaRepository;
|
||||||
|
|
||||||
|
private final UUID SAGA_ID = UUID.fromString("15a497c1-0f4b-4eff-b9f4-c402c8c07afa");
|
||||||
|
private final UUID ORDER_ID = UUID.fromString("d215b5f8-0249-4dc5-89a3-51fd148cfb17");
|
||||||
|
private final UUID CUSTOMER_ID = UUID.fromString("d215b5f8-0249-4dc5-89a3-51fd148cfb41");
|
||||||
|
private final UUID PAYMENT_ID = UUID.randomUUID();
|
||||||
|
private final BigDecimal PRICE = new BigDecimal("100");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDoublePayment() {
|
||||||
|
orderPaymentSaga.process(getPaymentResponse());
|
||||||
|
orderPaymentSaga.process(getPaymentResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDoublePaymentWithThreads() throws InterruptedException {
|
||||||
|
Thread thread1 = new Thread(() -> orderPaymentSaga.process(getPaymentResponse()));
|
||||||
|
Thread thread2 = new Thread(() -> orderPaymentSaga.process(getPaymentResponse()));
|
||||||
|
|
||||||
|
thread1.start();
|
||||||
|
thread2.start();
|
||||||
|
|
||||||
|
thread1.join();
|
||||||
|
thread2.join();
|
||||||
|
|
||||||
|
assertPaymentOutbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDoublePaymentWithLatch() throws InterruptedException {
|
||||||
|
CountDownLatch latch = new CountDownLatch(2);
|
||||||
|
|
||||||
|
Thread thread1 = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
orderPaymentSaga.process(getPaymentResponse());
|
||||||
|
} catch (OptimisticLockingFailureException e) {
|
||||||
|
log.error("OptimisticLockingFailureException occurred for thread1");
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Thread thread2 = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
orderPaymentSaga.process(getPaymentResponse());
|
||||||
|
} catch (OptimisticLockingFailureException e) {
|
||||||
|
log.error("OptimisticLockingFailureException occurred for thread2");
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
thread1.start();
|
||||||
|
thread2.start();
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
|
||||||
|
assertPaymentOutbox();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertPaymentOutbox() {
|
||||||
|
Optional<PaymentOutboxEntity> paymentOutboxEntity =
|
||||||
|
paymentOutboxJpaRepository.findByTypeAndSagaIdAndSagaStatusIn(ORDER_PROCESSING_SAGA, SAGA_ID,
|
||||||
|
List.of(SagaStatus.PROCESSING));
|
||||||
|
assertTrue(paymentOutboxEntity.isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private PaymentResponse getPaymentResponse() {
|
||||||
|
return PaymentResponse.builder()
|
||||||
|
.id(UUID.randomUUID().toString())
|
||||||
|
.sagaId(SAGA_ID.toString())
|
||||||
|
.paymentStatus(PaymentStatus.COMPLETED)
|
||||||
|
.paymentId(PAYMENT_ID.toString())
|
||||||
|
.orderId(ORDER_ID.toString())
|
||||||
|
.customerId(CUSTOMER_ID.toString())
|
||||||
|
.price(PRICE)
|
||||||
|
.createdAt(Instant.now())
|
||||||
|
.failureMessages(new ArrayList<>())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
delete from "order".orders where id = 'd215b5f8-0249-4dc5-89a3-51fd148cfb17';
|
||||||
|
|
||||||
|
delete from "order".payment_outbox where id = '8904808e-286f-449b-9b56-b63ba8351cf2';
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
insert into "order".orders(id, customer_id, restaurant_id, tracking_id, price, order_status, failure_messages)
|
||||||
|
values('d215b5f8-0249-4dc5-89a3-51fd148cfb17', 'd215b5f8-0249-4dc5-89a3-51fd148cfb41', 'd215b5f8-0249-4dc5-89a3-51fd148cfb45',
|
||||||
|
'd215b5f8-0249-4dc5-89a3-51fd148cfb18', 100.00, 'PENDING', '');
|
||||||
|
|
||||||
|
insert into "order".order_items(id, order_id, product_id, price, quantity, sub_total)
|
||||||
|
values(1, 'd215b5f8-0249-4dc5-89a3-51fd148cfb17', 'd215b5f8-0249-4dc5-89a3-51fd148cfb47', 100.00, 1, 100.00);
|
||||||
|
|
||||||
|
insert into "order".order_address(id, order_id, street, postal_code, city)
|
||||||
|
values('d215b5f8-0249-4dc5-89a3-51fd148cfb15', 'd215b5f8-0249-4dc5-89a3-51fd148cfb17', 'test street', '1000AA', 'test city');
|
||||||
|
|
||||||
|
insert into "order".payment_outbox(id, saga_id, created_at, type, payload, outbox_status, saga_status, order_status, version)
|
||||||
|
values ('8904808e-286f-449b-9b56-b63ba8351cf2', '15a497c1-0f4b-4eff-b9f4-c402c8c07afa', current_timestamp, 'OrderProcessingSaga',
|
||||||
|
'{"price": 100, "orderId": "ef471dac-ec22-43a7-a3f4-9d04195567a5", "createdAt": "2022-01-07T16:21:42.917756+01:00",
|
||||||
|
"customerId": "d215b5f8-0249-4dc5-89a3-51fd148cfb41", "paymentOrderStatus": "PENDING"}',
|
||||||
|
'STARTED', 'STARTED', 'PENDING', 0);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.data.access.customer.adapter;
|
package com.food.order.system.data.access.customer.adapter;
|
||||||
|
|
||||||
import com.food.order.sysyem.ports.output.repository.CustomerRepository;
|
import com.food.order.system.ports.output.repository.CustomerRepository;
|
||||||
import com.food.order.system.data.access.customer.mapper.CustomerDataAccessMapper;
|
import com.food.order.system.data.access.customer.mapper.CustomerDataAccessMapper;
|
||||||
import com.food.order.system.data.access.customer.repository.CustomerJPARepository;
|
import com.food.order.system.data.access.customer.repository.CustomerJPARepository;
|
||||||
import com.food.order.system.domain.entity.Customer;
|
import com.food.order.system.domain.entity.Customer;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.data.access.customer.mapper;
|
package com.food.order.system.data.access.customer.mapper;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.CustomerId;
|
import com.food.order.system.valueobject.CustomerId;
|
||||||
import com.food.order.system.data.access.customer.entity.CustomerEntity;
|
import com.food.order.system.data.access.customer.entity.CustomerEntity;
|
||||||
import com.food.order.system.domain.entity.Customer;
|
import com.food.order.system.domain.entity.Customer;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package com.food.order.system.data.access.order.adapter;
|
package com.food.order.system.data.access.order.adapter;
|
||||||
|
|
||||||
import com.food.order.sysyem.ports.output.repository.OrderRepository;
|
|
||||||
import com.food.order.system.data.access.order.mapper.OrderDataAccessMapper;
|
import com.food.order.system.data.access.order.mapper.OrderDataAccessMapper;
|
||||||
import com.food.order.system.data.access.order.repository.OrderJpaRepository;
|
import com.food.order.system.data.access.order.repository.OrderJpaRepository;
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
import com.food.order.system.domain.valueobject.TrackingId;
|
import com.food.order.system.domain.valueobject.TrackingId;
|
||||||
|
import com.food.order.system.ports.output.repository.OrderRepository;
|
||||||
|
import com.food.order.system.valueobject.OrderId;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -28,8 +28,8 @@ public class OrderRepositoryImpl implements OrderRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Order> findById(String orderId) {
|
public Optional<Order> findById(OrderId orderId) {
|
||||||
return orderJpaRepository.findById(UUID.fromString(orderId))
|
return orderJpaRepository.findById(orderId.getValue())
|
||||||
.map(orderDataAccessMapper::orderEntityToOrder);
|
.map(orderDataAccessMapper::orderEntityToOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.data.access.order.entity;
|
package com.food.order.system.data.access.order.entity;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.hibernate.annotations.DynamicUpdate;
|
import org.hibernate.annotations.DynamicUpdate;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import com.food.order.system.domain.entity.Product;
|
|||||||
import com.food.order.system.domain.valueobject.OrderItemId;
|
import com.food.order.system.domain.valueobject.OrderItemId;
|
||||||
import com.food.order.system.domain.valueobject.StreetAddress;
|
import com.food.order.system.domain.valueobject.StreetAddress;
|
||||||
import com.food.order.system.domain.valueobject.TrackingId;
|
import com.food.order.system.domain.valueobject.TrackingId;
|
||||||
import com.food.order.sysyem.valueobject.*;
|
import com.food.order.system.valueobject.*;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import com.food.order.system.data.access.outbox.payment.mapper.PaymentOutboxData
|
|||||||
import com.food.order.system.data.access.outbox.payment.repository.PaymentOutboxJpaRepository;
|
import com.food.order.system.data.access.outbox.payment.repository.PaymentOutboxJpaRepository;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
import com.food.order.sysyem.ports.output.repository.PaymentOutboxRepository;
|
import com.food.order.system.ports.output.repository.PaymentOutboxRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package com.food.order.system.data.access.outbox.payment.entity;
|
|||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.food.order.system.data.access.outbox.payment.mapper;
|
package com.food.order.system.data.access.outbox.payment.mapper;
|
||||||
|
|
||||||
import com.food.order.system.data.access.outbox.payment.entity.PaymentOutboxEntity;
|
import com.food.order.system.data.access.outbox.payment.entity.PaymentOutboxEntity;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import com.food.order.system.data.access.outbox.restaurantapproval.mapper.Approv
|
|||||||
import com.food.order.system.data.access.outbox.restaurantapproval.repository.ApprovalOutboxJpaRepository;
|
import com.food.order.system.data.access.outbox.restaurantapproval.repository.ApprovalOutboxJpaRepository;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
import com.food.order.sysyem.ports.output.repository.ApprovalOutboxRepository;
|
import com.food.order.system.ports.output.repository.ApprovalOutboxRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package com.food.order.system.data.access.outbox.restaurantapproval.entity;
|
|||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.food.order.system.data.access.outbox.restaurantapproval.mapper;
|
package com.food.order.system.data.access.outbox.restaurantapproval.mapper;
|
||||||
|
|
||||||
import com.food.order.system.data.access.outbox.restaurantapproval.entity.ApprovalOutboxEntity;
|
import com.food.order.system.data.access.outbox.restaurantapproval.entity.ApprovalOutboxEntity;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package com.food.order.system.data.access.restaurant.adapter;
|
|||||||
import com.food.order.system.common.data.access.repository.RestaurantJpaRepository;
|
import com.food.order.system.common.data.access.repository.RestaurantJpaRepository;
|
||||||
import com.food.order.system.data.access.restaurant.mapper.RestaurantDataAccessMapper;
|
import com.food.order.system.data.access.restaurant.mapper.RestaurantDataAccessMapper;
|
||||||
import com.food.order.system.domain.entity.Restaurant;
|
import com.food.order.system.domain.entity.Restaurant;
|
||||||
import com.food.order.sysyem.ports.output.repository.RestaurantRepository;
|
import com.food.order.system.ports.output.repository.RestaurantRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import com.food.order.system.common.data.access.entity.RestaurantEntity;
|
|||||||
import com.food.order.system.common.data.access.exception.RestaurantDataAccessException;
|
import com.food.order.system.common.data.access.exception.RestaurantDataAccessException;
|
||||||
import com.food.order.system.domain.entity.Product;
|
import com.food.order.system.domain.entity.Product;
|
||||||
import com.food.order.system.domain.entity.Restaurant;
|
import com.food.order.system.domain.entity.Restaurant;
|
||||||
import com.food.order.sysyem.valueobject.Money;
|
import com.food.order.system.valueobject.Money;
|
||||||
import com.food.order.sysyem.valueobject.ProductId;
|
import com.food.order.system.valueobject.ProductId;
|
||||||
import com.food.order.sysyem.valueobject.RestaurantId;
|
import com.food.order.system.valueobject.RestaurantId;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.food.order.sysyem;
|
package com.food.order.system;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderCommand;
|
import com.food.order.system.dto.create.CreateOrderCommand;
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderResponse;
|
import com.food.order.system.dto.create.CreateOrderResponse;
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderQuery;
|
import com.food.order.system.dto.track.TrackOrderQuery;
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderResponse;
|
import com.food.order.system.dto.track.TrackOrderResponse;
|
||||||
import com.food.order.sysyem.ports.input.service.OrderApplicationService;
|
import com.food.order.system.ports.input.service.OrderApplicationService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.food.order.sysyem;
|
package com.food.order.system;
|
||||||
|
|
||||||
|
import com.food.order.system.dto.create.CreateOrderCommand;
|
||||||
|
import com.food.order.system.dto.create.CreateOrderResponse;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderCommand;
|
import com.food.order.system.helper.OrderCreateHelper;
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderResponse;
|
import com.food.order.system.helper.OrderSagaHelper;
|
||||||
import com.food.order.sysyem.helper.OrderCreateHelper;
|
import com.food.order.system.mapper.OrderDataMapper;
|
||||||
import com.food.order.sysyem.helper.OrderSagaHelper;
|
import com.food.order.system.outbox.scheduler.payment.PaymentOutboxHelper;
|
||||||
import com.food.order.sysyem.mapper.OrderDataMapper;
|
|
||||||
import com.food.order.sysyem.outbox.scheduler.payment.PaymentOutboxHelper;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.food.order.sysyem;
|
package com.food.order.system;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderQuery;
|
import com.food.order.system.dto.track.TrackOrderQuery;
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderResponse;
|
import com.food.order.system.dto.track.TrackOrderResponse;
|
||||||
import com.food.order.sysyem.mapper.OrderDataMapper;
|
import com.food.order.system.mapper.OrderDataMapper;
|
||||||
import com.food.order.sysyem.ports.output.repository.OrderRepository;
|
import com.food.order.system.ports.output.repository.OrderRepository;
|
||||||
import com.food.order.system.domain.exception.OrderNotFoundException;
|
import com.food.order.system.domain.exception.OrderNotFoundException;
|
||||||
import com.food.order.system.domain.valueobject.TrackingId;
|
import com.food.order.system.domain.valueobject.TrackingId;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.sysyem;
|
package com.food.order.system;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.message.PaymentResponse;
|
import com.food.order.system.dto.message.PaymentResponse;
|
||||||
import com.food.order.sysyem.ports.input.message.listener.payment.PaymentResponseMessageListener;
|
import com.food.order.system.ports.input.message.listener.payment.PaymentResponseMessageListener;
|
||||||
import com.food.order.sysyem.saga.OrderPaymentSaga;
|
import com.food.order.system.saga.OrderPaymentSaga;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.sysyem;
|
package com.food.order.system;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.message.RestaurantApprovalResponse;
|
import com.food.order.system.dto.message.RestaurantApprovalResponse;
|
||||||
import com.food.order.sysyem.ports.input.message.listener.restaurantapproval.RestaurantApprovalResponseMessageListener;
|
import com.food.order.system.ports.input.message.listener.restaurantapproval.RestaurantApprovalResponseMessageListener;
|
||||||
import com.food.order.sysyem.saga.OrderApprovalSaga;
|
import com.food.order.system.saga.OrderApprovalSaga;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.config;
|
package com.food.order.system.config;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.dto.create;
|
package com.food.order.system.dto.create;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.sysyem.dto.create;
|
package com.food.order.system.dto.create;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.dto.create;
|
package com.food.order.system.dto.create;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.dto.create;
|
package com.food.order.system.dto.create;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.sysyem.dto.message;
|
package com.food.order.system.dto.message;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.PaymentStatus;
|
import com.food.order.system.valueobject.PaymentStatus;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.sysyem.dto.message;
|
package com.food.order.system.dto.message;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.OrderApprovalStatus;
|
import com.food.order.system.valueobject.OrderApprovalStatus;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.dto.track;
|
package com.food.order.system.dto.track;
|
||||||
|
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.sysyem.dto.track;
|
package com.food.order.system.dto.track;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
package com.food.order.sysyem.helper;
|
package com.food.order.system.helper;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderCommand;
|
import com.food.order.system.dto.create.CreateOrderCommand;
|
||||||
import com.food.order.sysyem.event.publisher.DomainEventPublisher;
|
import com.food.order.system.mapper.OrderDataMapper;
|
||||||
import com.food.order.sysyem.mapper.OrderDataMapper;
|
import com.food.order.system.ports.output.repository.CustomerRepository;
|
||||||
import com.food.order.sysyem.ports.output.repository.CustomerRepository;
|
import com.food.order.system.ports.output.repository.OrderRepository;
|
||||||
import com.food.order.sysyem.ports.output.repository.OrderRepository;
|
import com.food.order.system.ports.output.repository.RestaurantRepository;
|
||||||
import com.food.order.sysyem.ports.output.repository.RestaurantRepository;
|
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
import com.food.order.system.domain.entity.Restaurant;
|
import com.food.order.system.domain.entity.Restaurant;
|
||||||
import com.food.order.system.domain.event.OrderCreatedEvent;
|
import com.food.order.system.domain.event.OrderCreatedEvent;
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
package com.food.order.sysyem.helper;
|
package com.food.order.system.helper;
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
import com.food.order.system.domain.exception.OrderNotFoundException;
|
import com.food.order.system.domain.exception.OrderNotFoundException;
|
||||||
|
import com.food.order.system.ports.output.repository.OrderRepository;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.ports.output.repository.OrderRepository;
|
import com.food.order.system.valueobject.OrderId;
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@@ -17,7 +20,7 @@ public class OrderSagaHelper {
|
|||||||
private final OrderRepository orderRepository;
|
private final OrderRepository orderRepository;
|
||||||
|
|
||||||
public Order findOrder(String orderId) {
|
public Order findOrder(String orderId) {
|
||||||
return orderRepository.findById(orderId)
|
return orderRepository.findById(new OrderId(UUID.fromString(orderId)))
|
||||||
.orElseThrow(() -> new OrderNotFoundException("Order not found -> Order id :" + orderId));
|
.orElseThrow(() -> new OrderNotFoundException("Order not found -> Order id :" + orderId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,20 +1,21 @@
|
|||||||
package com.food.order.sysyem.mapper;
|
package com.food.order.system.mapper;
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
import com.food.order.system.domain.entity.OrderItem;
|
import com.food.order.system.domain.entity.OrderItem;
|
||||||
import com.food.order.system.domain.entity.Product;
|
import com.food.order.system.domain.entity.Product;
|
||||||
import com.food.order.system.domain.entity.Restaurant;
|
import com.food.order.system.domain.entity.Restaurant;
|
||||||
|
import com.food.order.system.domain.event.OrderCancelledEvent;
|
||||||
import com.food.order.system.domain.event.OrderCreatedEvent;
|
import com.food.order.system.domain.event.OrderCreatedEvent;
|
||||||
import com.food.order.system.domain.event.OrderPaidEvent;
|
import com.food.order.system.domain.event.OrderPaidEvent;
|
||||||
import com.food.order.system.domain.valueobject.StreetAddress;
|
import com.food.order.system.domain.valueobject.StreetAddress;
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderCommand;
|
import com.food.order.system.dto.create.CreateOrderCommand;
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderResponse;
|
import com.food.order.system.dto.create.CreateOrderResponse;
|
||||||
import com.food.order.sysyem.dto.create.OrderAddress;
|
import com.food.order.system.dto.create.OrderAddress;
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderResponse;
|
import com.food.order.system.dto.track.TrackOrderResponse;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalEventPayload;
|
import com.food.order.system.outbox.model.approval.OrderApprovalEventPayload;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalProduct;
|
import com.food.order.system.outbox.model.approval.OrderApprovalProduct;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentEventPayload;
|
import com.food.order.system.outbox.model.payment.OrderPaymentEventPayload;
|
||||||
import com.food.order.sysyem.valueobject.*;
|
import com.food.order.system.valueobject.*;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -23,6 +24,17 @@ import java.util.UUID;
|
|||||||
@Component
|
@Component
|
||||||
public class OrderDataMapper {
|
public class OrderDataMapper {
|
||||||
|
|
||||||
|
public OrderPaymentEventPayload orderCancelledEventToOrderPaymentEventPayload(
|
||||||
|
OrderCancelledEvent orderCancelledEvent) {
|
||||||
|
return OrderPaymentEventPayload.builder()
|
||||||
|
.orderId(orderCancelledEvent.getOrder().getId().getValue().toString())
|
||||||
|
.paymentOrderStatus(PaymentOrderStatus.CANCELLED.name())
|
||||||
|
.customerId(orderCancelledEvent.getOrder().getCustomerId().getValue().toString())
|
||||||
|
.price(orderCancelledEvent.getOrder().getPrice().getAmount())
|
||||||
|
.createdAt(orderCancelledEvent.getCreatedAt())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
public OrderApprovalEventPayload orderPaidEventToOrderApprovalEventPayload(OrderPaidEvent orderPaidEvent) {
|
public OrderApprovalEventPayload orderPaidEventToOrderApprovalEventPayload(OrderPaidEvent orderPaidEvent) {
|
||||||
return OrderApprovalEventPayload.builder()
|
return OrderApprovalEventPayload.builder()
|
||||||
.orderId(orderPaidEvent.getOrder().getId().getValue().toString())
|
.orderId(orderPaidEvent.getOrder().getId().getValue().toString())
|
||||||
@@ -80,7 +92,7 @@ public class OrderDataMapper {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<OrderItem> orderItemsToOrderItemEntities(List<com.food.order.sysyem.dto.create.OrderItem> orderItems) {
|
private List<OrderItem> orderItemsToOrderItemEntities(List<com.food.order.system.dto.create.OrderItem> orderItems) {
|
||||||
return orderItems.stream()
|
return orderItems.stream()
|
||||||
.map(orderItem ->
|
.map(orderItem ->
|
||||||
OrderItem.builder()
|
OrderItem.builder()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.outbox.model.approval;
|
package com.food.order.system.outbox.model.approval;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.sysyem.outbox.model.approval;
|
package com.food.order.system.outbox.model.approval;
|
||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.outbox.model.approval;
|
package com.food.order.system.outbox.model.approval;
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.outbox.model.payment;
|
package com.food.order.system.outbox.model.payment;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.sysyem.outbox.model.payment;
|
package com.food.order.system.outbox.model.payment;
|
||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.food.order.sysyem.outbox.scheduler.approval;
|
package com.food.order.system.outbox.scheduler.approval;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.approval.OrderApprovalEventPayload;
|
||||||
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalEventPayload;
|
import com.food.order.system.ports.output.repository.ApprovalOutboxRepository;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import com.food.order.sysyem.ports.output.repository.ApprovalOutboxRepository;
|
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -73,9 +73,9 @@ public class ApprovalOutboxHelper {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void saveApprovalOutboxMessage(OrderApprovalEventPayload payload,
|
public void saveApprovalOutboxMessage(OrderApprovalEventPayload payload,
|
||||||
OrderStatus orderStatus,
|
OrderStatus orderStatus,
|
||||||
SagaStatus sagaStatus,
|
SagaStatus sagaStatus,
|
||||||
OutboxStatus outboxStatus,
|
OutboxStatus outboxStatus,
|
||||||
UUID sagaId) {
|
UUID sagaId) {
|
||||||
|
|
||||||
save(OrderApprovalOutboxMessage.builder()
|
save(OrderApprovalOutboxMessage.builder()
|
||||||
.id(UUID.randomUUID())
|
.id(UUID.randomUUID())
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.food.order.sysyem.outbox.scheduler.approval;
|
package com.food.order.system.outbox.scheduler.approval;
|
||||||
|
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
import com.food.order.system.outbox.OutboxScheduler;
|
import com.food.order.system.outbox.OutboxScheduler;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
@@ -16,7 +16,7 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RestaurantApprovalOutboxCleaner implements OutboxScheduler {
|
public class RestaurantApprovalOutboxCleanerSchedule implements OutboxScheduler {
|
||||||
|
|
||||||
private final ApprovalOutboxHelper approvalOutboxHelper;
|
private final ApprovalOutboxHelper approvalOutboxHelper;
|
||||||
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.food.order.sysyem.outbox.scheduler.approval;
|
package com.food.order.system.outbox.scheduler.approval;
|
||||||
|
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
import com.food.order.system.outbox.OutboxScheduler;
|
import com.food.order.system.outbox.OutboxScheduler;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
import com.food.order.system.ports.output.message.publisher.restaurantapproval.RestaurantApprovalRequestMessagePublisher;
|
||||||
import com.food.order.sysyem.ports.output.message.publisher.restaurantapproval.RestaurantApprovalRequestMessagePublisher;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
@@ -18,7 +18,7 @@ import java.util.stream.Collectors;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RestaurantApprovalOutboxMessage implements OutboxScheduler {
|
public class RestaurantApprovalOutboxScheduler implements OutboxScheduler {
|
||||||
|
|
||||||
private final ApprovalOutboxHelper approvalOutboxHelper;
|
private final ApprovalOutboxHelper approvalOutboxHelper;
|
||||||
private final RestaurantApprovalRequestMessagePublisher restaurantApprovalRequestMessagePublisher;
|
private final RestaurantApprovalRequestMessagePublisher restaurantApprovalRequestMessagePublisher;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.food.order.sysyem.outbox.scheduler.payment;
|
package com.food.order.system.outbox.scheduler.payment;
|
||||||
|
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
import com.food.order.system.outbox.OutboxScheduler;
|
import com.food.order.system.outbox.OutboxScheduler;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package com.food.order.sysyem.outbox.scheduler.payment;
|
package com.food.order.system.outbox.scheduler.payment;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentEventPayload;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
|
import com.food.order.system.ports.output.repository.PaymentOutboxRepository;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentEventPayload;
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
|
||||||
import com.food.order.sysyem.ports.output.repository.PaymentOutboxRepository;
|
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
package com.food.order.sysyem.outbox.scheduler.payment;
|
package com.food.order.system.outbox.scheduler.payment;
|
||||||
|
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
import com.food.order.system.outbox.OutboxScheduler;
|
import com.food.order.system.outbox.OutboxScheduler;
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
|
import com.food.order.system.ports.output.message.publisher.payment.PaymentRequestMessagePublisher;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
|
||||||
import com.food.order.sysyem.ports.output.message.publisher.payment.PaymentRequestMessagePublisher;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -17,12 +16,17 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
//@RequiredArgsConstructor
|
||||||
public class PaymentOutboxScheduler implements OutboxScheduler {
|
public class PaymentOutboxScheduler implements OutboxScheduler {
|
||||||
|
|
||||||
private final PaymentOutboxHelper paymentOutboxHelper;
|
private final PaymentOutboxHelper paymentOutboxHelper;
|
||||||
private final PaymentRequestMessagePublisher paymentRequestMessagePublisher;
|
private final PaymentRequestMessagePublisher paymentRequestMessagePublisher;
|
||||||
|
|
||||||
|
public PaymentOutboxScheduler(PaymentOutboxHelper paymentOutboxHelper, PaymentRequestMessagePublisher paymentRequestMessagePublisher) {
|
||||||
|
this.paymentOutboxHelper = paymentOutboxHelper;
|
||||||
|
this.paymentRequestMessagePublisher = paymentRequestMessagePublisher;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
@Scheduled(fixedDelayString = "${order-service.outbox-scheduler-fixed-rate}",
|
@Scheduled(fixedDelayString = "${order-service.outbox-scheduler-fixed-rate}",
|
||||||
@@ -39,7 +43,7 @@ public class PaymentOutboxScheduler implements OutboxScheduler {
|
|||||||
.orElseThrow(
|
.orElseThrow(
|
||||||
() -> new OrderDomainException("No outbox message found for processing"));
|
() -> new OrderDomainException("No outbox message found for processing"));
|
||||||
|
|
||||||
if (Objects.nonNull(outboxMessageResponse) && outboxMessageResponse.size() > 0) {
|
if (Objects.nonNull(outboxMessageResponse) && !outboxMessageResponse.isEmpty()) {
|
||||||
|
|
||||||
log.info("Received {} OrderPaymentOutboxMessage with ids : {} , sending message bus !" ,
|
log.info("Received {} OrderPaymentOutboxMessage with ids : {} , sending message bus !" ,
|
||||||
outboxMessageResponse.size(),
|
outboxMessageResponse.size(),
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.sysyem.ports.input.message.listener.payment;
|
package com.food.order.system.ports.input.message.listener.payment;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.message.PaymentResponse;
|
import com.food.order.system.dto.message.PaymentResponse;
|
||||||
|
|
||||||
public interface PaymentResponseMessageListener {
|
public interface PaymentResponseMessageListener {
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.sysyem.ports.input.message.listener.restaurantapproval;
|
package com.food.order.system.ports.input.message.listener.restaurantapproval;
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.message.RestaurantApprovalResponse;
|
import com.food.order.system.dto.message.RestaurantApprovalResponse;
|
||||||
|
|
||||||
public interface RestaurantApprovalResponseMessageListener {
|
public interface RestaurantApprovalResponseMessageListener {
|
||||||
void orderApproved(RestaurantApprovalResponse restaurantApprovalResponse);
|
void orderApproved(RestaurantApprovalResponse restaurantApprovalResponse);
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.food.order.system.ports.input.service;
|
||||||
|
|
||||||
|
import com.food.order.system.dto.create.CreateOrderCommand;
|
||||||
|
import com.food.order.system.dto.create.CreateOrderResponse;
|
||||||
|
import com.food.order.system.dto.track.TrackOrderQuery;
|
||||||
|
import com.food.order.system.dto.track.TrackOrderResponse;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
public interface OrderApplicationService {
|
||||||
|
|
||||||
|
CreateOrderResponse createOrder(@Valid CreateOrderCommand createOrderCommand);
|
||||||
|
TrackOrderResponse trackOrder(@Valid TrackOrderQuery trackOrderQuery);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.food.order.sysyem.ports.output.message.publisher.payment;
|
package com.food.order.system.ports.output.message.publisher.payment;
|
||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.food.order.sysyem.ports.output.message.publisher.restaurantapproval;
|
package com.food.order.system.ports.output.message.publisher.restaurantapproval;
|
||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.sysyem.ports.output.repository;
|
package com.food.order.system.ports.output.repository;
|
||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.ports.output.repository;
|
package com.food.order.system.ports.output.repository;
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Customer;
|
import com.food.order.system.domain.entity.Customer;
|
||||||
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.food.order.sysyem.ports.output.repository;
|
package com.food.order.system.ports.output.repository;
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
import com.food.order.system.domain.valueobject.TrackingId;
|
import com.food.order.system.domain.valueobject.TrackingId;
|
||||||
|
import com.food.order.system.valueobject.OrderId;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ public interface OrderRepository {
|
|||||||
|
|
||||||
Order save(Order order);
|
Order save(Order order);
|
||||||
|
|
||||||
Optional<Order> findById(String trackingId);
|
Optional<Order> findById(OrderId trackingId);
|
||||||
|
|
||||||
Optional<Order> findByTrackingId(TrackingId trackingId);
|
Optional<Order> findByTrackingId(TrackingId trackingId);
|
||||||
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.sysyem.ports.output.repository;
|
package com.food.order.system.ports.output.repository;
|
||||||
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
import com.food.order.system.saga.SagaStatus;
|
import com.food.order.system.saga.SagaStatus;
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.food.order.sysyem.ports.output.repository;
|
package com.food.order.system.ports.output.repository;
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Restaurant;
|
import com.food.order.system.domain.entity.Restaurant;
|
||||||
|
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.food.order.system.saga;
|
||||||
|
|
||||||
|
import com.food.order.system.domain.entity.Order;
|
||||||
|
import com.food.order.system.domain.event.OrderCancelledEvent;
|
||||||
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
|
import com.food.order.system.domain.service.OrderDomainService;
|
||||||
|
import com.food.order.system.dto.message.RestaurantApprovalResponse;
|
||||||
|
import com.food.order.system.helper.OrderSagaHelper;
|
||||||
|
import com.food.order.system.mapper.OrderDataMapper;
|
||||||
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
|
import com.food.order.system.outbox.scheduler.approval.ApprovalOutboxHelper;
|
||||||
|
import com.food.order.system.outbox.scheduler.payment.PaymentOutboxHelper;
|
||||||
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static com.food.order.system.DomainConstants.UTC;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class OrderApprovalSaga implements SagaStep<RestaurantApprovalResponse> {
|
||||||
|
|
||||||
|
private final OrderDomainService orderDomainService;
|
||||||
|
private final OrderSagaHelper orderSagaHelper;
|
||||||
|
private final PaymentOutboxHelper paymentOutboxHelper;
|
||||||
|
private final OrderDataMapper orderDataMapper;
|
||||||
|
private final ApprovalOutboxHelper approvalOutboxHelper;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void process(RestaurantApprovalResponse restaurantApprovalResponse) {
|
||||||
|
var orderApprovalOutboxMessageResponse =
|
||||||
|
approvalOutboxHelper.getApprovalOutboxMessageBySagaIdAndSagaStatus(
|
||||||
|
UUID.fromString(restaurantApprovalResponse.getSagaId()),
|
||||||
|
SagaStatus.PROCESSING).orElseThrow(
|
||||||
|
() -> new OrderDomainException("OrderApprovalSaga: Order approval outbox message not found"));
|
||||||
|
|
||||||
|
var order = approveOrder(restaurantApprovalResponse);
|
||||||
|
|
||||||
|
var sagaStatus = orderSagaHelper.orderStatusToSagaStatus(order.getStatus());
|
||||||
|
|
||||||
|
approvalOutboxHelper.save(getUpdatedApprovalOutboxMessage(orderApprovalOutboxMessageResponse,
|
||||||
|
order.getStatus(), sagaStatus));
|
||||||
|
|
||||||
|
paymentOutboxHelper.save(getUpdatedPaymentOutboxMessage(restaurantApprovalResponse.getSagaId(),
|
||||||
|
order.getStatus(), sagaStatus));
|
||||||
|
|
||||||
|
log.info("Order with id: {} is approved", order.getId().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void rollback(RestaurantApprovalResponse restaurantApprovalResponse) {
|
||||||
|
var orderApprovalOutboxMessageResponse =
|
||||||
|
approvalOutboxHelper.getApprovalOutboxMessageBySagaIdAndSagaStatus(
|
||||||
|
UUID.fromString(restaurantApprovalResponse.getSagaId()),
|
||||||
|
SagaStatus.PROCESSING).orElseThrow(
|
||||||
|
() -> new OrderDomainException("OrderApprovalSaga: Order approval outbox message not found"));
|
||||||
|
|
||||||
|
var domainEvent = rollbackOrder(restaurantApprovalResponse);
|
||||||
|
|
||||||
|
var sagaStatus = orderSagaHelper.orderStatusToSagaStatus(domainEvent.getOrder().getStatus());
|
||||||
|
|
||||||
|
approvalOutboxHelper.save(getUpdatedApprovalOutboxMessage(orderApprovalOutboxMessageResponse,
|
||||||
|
domainEvent.getOrder().getStatus(), sagaStatus));
|
||||||
|
|
||||||
|
paymentOutboxHelper.savePaymentOutboxMessage(orderDataMapper
|
||||||
|
.orderCancelledEventToOrderPaymentEventPayload(domainEvent),
|
||||||
|
domainEvent.getOrder().getStatus(),
|
||||||
|
sagaStatus,
|
||||||
|
OutboxStatus.STARTED,
|
||||||
|
UUID.fromString(restaurantApprovalResponse.getSagaId()));
|
||||||
|
|
||||||
|
log.info("Order with id: {} is cancelling", domainEvent.getOrder().getId().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Order approveOrder(RestaurantApprovalResponse restaurantApprovalResponse) {
|
||||||
|
log.info("Approving order with id: {}", restaurantApprovalResponse.getOrderId());
|
||||||
|
Order order = orderSagaHelper.findOrder(restaurantApprovalResponse.getOrderId());
|
||||||
|
orderDomainService.approve(order);
|
||||||
|
orderSagaHelper.saveOrder(order);
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderApprovalOutboxMessage getUpdatedApprovalOutboxMessage(OrderApprovalOutboxMessage
|
||||||
|
orderApprovalOutboxMessage,
|
||||||
|
OrderStatus
|
||||||
|
orderStatus,
|
||||||
|
SagaStatus
|
||||||
|
sagaStatus) {
|
||||||
|
orderApprovalOutboxMessage.setProcessedAt(ZonedDateTime.now(ZoneId.of(UTC)));
|
||||||
|
orderApprovalOutboxMessage.setOrderStatus(orderStatus);
|
||||||
|
orderApprovalOutboxMessage.setSagaStatus(sagaStatus);
|
||||||
|
return orderApprovalOutboxMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderPaymentOutboxMessage getUpdatedPaymentOutboxMessage(String sagaId,
|
||||||
|
OrderStatus orderStatus,
|
||||||
|
SagaStatus sagaStatus) {
|
||||||
|
Optional<OrderPaymentOutboxMessage> orderPaymentOutboxMessageResponse = paymentOutboxHelper
|
||||||
|
.getPaymentOutboxMessageBySagaIdAndSagaStatus(UUID.fromString(sagaId), SagaStatus.PROCESSING);
|
||||||
|
if (orderPaymentOutboxMessageResponse.isEmpty()) {
|
||||||
|
throw new OrderDomainException("Payment outbox message cannot be found in " +
|
||||||
|
SagaStatus.PROCESSING.name() + " state");
|
||||||
|
}
|
||||||
|
OrderPaymentOutboxMessage orderPaymentOutboxMessage = orderPaymentOutboxMessageResponse.get();
|
||||||
|
orderPaymentOutboxMessage.setProcessedAt(ZonedDateTime.now(ZoneId.of(UTC)));
|
||||||
|
orderPaymentOutboxMessage.setOrderStatus(orderStatus);
|
||||||
|
orderPaymentOutboxMessage.setSagaStatus(sagaStatus);
|
||||||
|
return orderPaymentOutboxMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderCancelledEvent rollbackOrder(RestaurantApprovalResponse restaurantApprovalResponse) {
|
||||||
|
log.info("Cancelling order with id: {}", restaurantApprovalResponse.getOrderId());
|
||||||
|
Order order = orderSagaHelper.findOrder(restaurantApprovalResponse.getOrderId());
|
||||||
|
OrderCancelledEvent domainEvent = orderDomainService.cancelOrderPayment(order,
|
||||||
|
restaurantApprovalResponse.getFailureMessages());
|
||||||
|
orderSagaHelper.saveOrder(order);
|
||||||
|
return domainEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package com.food.order.system.saga;
|
||||||
|
|
||||||
|
import com.food.order.system.domain.entity.Order;
|
||||||
|
import com.food.order.system.domain.event.OrderPaidEvent;
|
||||||
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
|
import com.food.order.system.domain.exception.OrderNotFoundException;
|
||||||
|
import com.food.order.system.domain.service.OrderDomainService;
|
||||||
|
import com.food.order.system.dto.message.PaymentResponse;
|
||||||
|
import com.food.order.system.helper.OrderSagaHelper;
|
||||||
|
import com.food.order.system.mapper.OrderDataMapper;
|
||||||
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.approval.OrderApprovalOutboxMessage;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
|
import com.food.order.system.outbox.scheduler.approval.ApprovalOutboxHelper;
|
||||||
|
import com.food.order.system.outbox.scheduler.payment.PaymentOutboxHelper;
|
||||||
|
import com.food.order.system.ports.output.repository.OrderRepository;
|
||||||
|
import com.food.order.system.valueobject.OrderId;
|
||||||
|
import com.food.order.system.valueobject.OrderStatus;
|
||||||
|
import com.food.order.system.valueobject.PaymentStatus;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static com.food.order.system.DomainConstants.UTC;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class OrderPaymentSaga implements SagaStep<PaymentResponse> {
|
||||||
|
private final OrderDomainService orderDomainService;
|
||||||
|
private final OrderRepository orderRepository;
|
||||||
|
private final PaymentOutboxHelper paymentOutboxHelper;
|
||||||
|
private final ApprovalOutboxHelper approvalOutboxHelper;
|
||||||
|
private final OrderSagaHelper orderSagaHelper;
|
||||||
|
private final OrderDataMapper orderDataMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void process(PaymentResponse paymentResponse) {
|
||||||
|
Optional<OrderPaymentOutboxMessage> orderPaymentOutboxMessageResponse =
|
||||||
|
paymentOutboxHelper.getPaymentOutboxMessageBySagaIdAndSagaStatus(
|
||||||
|
UUID.fromString(paymentResponse.getSagaId()),
|
||||||
|
SagaStatus.STARTED);
|
||||||
|
|
||||||
|
if (orderPaymentOutboxMessageResponse.isEmpty()) {
|
||||||
|
log.info("An outbox message with saga id: {} is already processed!", paymentResponse.getSagaId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderPaymentOutboxMessage orderPaymentOutboxMessage = orderPaymentOutboxMessageResponse.get();
|
||||||
|
|
||||||
|
OrderPaidEvent domainEvent = completePaymentForOrder(paymentResponse);
|
||||||
|
|
||||||
|
SagaStatus sagaStatus = orderSagaHelper.orderStatusToSagaStatus(domainEvent.getOrder().getStatus());
|
||||||
|
|
||||||
|
paymentOutboxHelper.save(getUpdatedPaymentOutboxMessage(orderPaymentOutboxMessage,
|
||||||
|
domainEvent.getOrder().getStatus(), sagaStatus));
|
||||||
|
|
||||||
|
approvalOutboxHelper
|
||||||
|
.saveApprovalOutboxMessage(orderDataMapper.orderPaidEventToOrderApprovalEventPayload(domainEvent),
|
||||||
|
domainEvent.getOrder().getStatus(),
|
||||||
|
sagaStatus,
|
||||||
|
OutboxStatus.STARTED,
|
||||||
|
UUID.fromString(paymentResponse.getSagaId()));
|
||||||
|
|
||||||
|
log.info("Order with id: {} is paid", domainEvent.getOrder().getId().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void rollback(PaymentResponse paymentResponse) {
|
||||||
|
|
||||||
|
Optional<OrderPaymentOutboxMessage> orderPaymentOutboxMessageResponse =
|
||||||
|
paymentOutboxHelper.getPaymentOutboxMessageBySagaIdAndSagaStatus(
|
||||||
|
UUID.fromString(paymentResponse.getSagaId()),
|
||||||
|
getCurrentSagaStatus(paymentResponse.getPaymentStatus()));
|
||||||
|
|
||||||
|
if (orderPaymentOutboxMessageResponse.isEmpty()) {
|
||||||
|
log.info("An outbox message with saga id: {} is already roll backed!", paymentResponse.getSagaId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderPaymentOutboxMessage orderPaymentOutboxMessage = orderPaymentOutboxMessageResponse.get();
|
||||||
|
|
||||||
|
Order order = rollbackPaymentForOrder(paymentResponse);
|
||||||
|
|
||||||
|
SagaStatus sagaStatus = orderSagaHelper.orderStatusToSagaStatus(order.getStatus());
|
||||||
|
|
||||||
|
paymentOutboxHelper.save(getUpdatedPaymentOutboxMessage(orderPaymentOutboxMessage,
|
||||||
|
order.getStatus(), sagaStatus));
|
||||||
|
|
||||||
|
if (paymentResponse.getPaymentStatus() == PaymentStatus.CANCELED) {
|
||||||
|
approvalOutboxHelper.save(getUpdatedApprovalOutboxMessage(paymentResponse.getSagaId(),
|
||||||
|
order.getStatus(), sagaStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Order with id: {} is cancelled", order.getId().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Order findOrder(String orderId) {
|
||||||
|
Optional<Order> orderResponse = orderRepository.findById(new OrderId(UUID.fromString(orderId)));
|
||||||
|
if (orderResponse.isEmpty()) {
|
||||||
|
log.error("Order with id: {} could not be found!", orderId);
|
||||||
|
throw new OrderNotFoundException("Order with id " + orderId + " could not be found!");
|
||||||
|
}
|
||||||
|
return orderResponse.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderPaymentOutboxMessage getUpdatedPaymentOutboxMessage(OrderPaymentOutboxMessage
|
||||||
|
orderPaymentOutboxMessage,
|
||||||
|
OrderStatus
|
||||||
|
orderStatus,
|
||||||
|
SagaStatus
|
||||||
|
sagaStatus) {
|
||||||
|
orderPaymentOutboxMessage.setProcessedAt(ZonedDateTime.now(ZoneId.of(UTC)));
|
||||||
|
orderPaymentOutboxMessage.setOrderStatus(orderStatus);
|
||||||
|
orderPaymentOutboxMessage.setSagaStatus(sagaStatus);
|
||||||
|
return orderPaymentOutboxMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderPaidEvent completePaymentForOrder(PaymentResponse paymentResponse) {
|
||||||
|
log.info("Completing payment for order with id: {}", paymentResponse.getOrderId());
|
||||||
|
Order order = findOrder(paymentResponse.getOrderId());
|
||||||
|
OrderPaidEvent domainEvent = orderDomainService.payOrder(order);
|
||||||
|
orderRepository.save(order);
|
||||||
|
return domainEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SagaStatus[] getCurrentSagaStatus(PaymentStatus paymentStatus) {
|
||||||
|
return switch (paymentStatus) {
|
||||||
|
case COMPLETED -> new SagaStatus[] { SagaStatus.STARTED };
|
||||||
|
case CANCELED -> new SagaStatus[] { SagaStatus.PROCESSING };
|
||||||
|
case FAILED -> new SagaStatus[] { SagaStatus.STARTED, SagaStatus.PROCESSING };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Order rollbackPaymentForOrder(PaymentResponse paymentResponse) {
|
||||||
|
log.info("Cancelling order with id: {}", paymentResponse.getOrderId());
|
||||||
|
Order order = findOrder(paymentResponse.getOrderId());
|
||||||
|
orderDomainService.cancelOrder(order, paymentResponse.getFailureMessages());
|
||||||
|
orderRepository.save(order);
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderApprovalOutboxMessage getUpdatedApprovalOutboxMessage(String sagaId,
|
||||||
|
OrderStatus orderStatus,
|
||||||
|
SagaStatus sagaStatus) {
|
||||||
|
Optional<OrderApprovalOutboxMessage> orderApprovalOutboxMessageResponse =
|
||||||
|
approvalOutboxHelper.getApprovalOutboxMessageBySagaIdAndSagaStatus(
|
||||||
|
UUID.fromString(sagaId),
|
||||||
|
SagaStatus.COMPENSATING);
|
||||||
|
if (orderApprovalOutboxMessageResponse.isEmpty()) {
|
||||||
|
throw new OrderDomainException("Approval outbox message could not be found in " +
|
||||||
|
SagaStatus.COMPENSATING.name() + " status!");
|
||||||
|
}
|
||||||
|
OrderApprovalOutboxMessage orderApprovalOutboxMessage = orderApprovalOutboxMessageResponse.get();
|
||||||
|
orderApprovalOutboxMessage.setProcessedAt(ZonedDateTime.now(ZoneId.of(UTC)));
|
||||||
|
orderApprovalOutboxMessage.setOrderStatus(orderStatus);
|
||||||
|
orderApprovalOutboxMessage.setSagaStatus(sagaStatus);
|
||||||
|
return orderApprovalOutboxMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.food.order.sysyem.ports.input.service;
|
|
||||||
|
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderCommand;
|
|
||||||
import com.food.order.sysyem.dto.create.CreateOrderResponse;
|
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderQuery;
|
|
||||||
import com.food.order.sysyem.dto.track.TrackOrderResponse;
|
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
|
|
||||||
public interface OrderApplicationService {
|
|
||||||
|
|
||||||
CreateOrderResponse createOrder(@Valid CreateOrderCommand createOrderCommand);
|
|
||||||
TrackOrderResponse trackOrder(@Valid TrackOrderQuery trackOrderQuery);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package com.food.order.sysyem.saga;
|
|
||||||
|
|
||||||
import com.food.order.system.domain.service.OrderDomainService;
|
|
||||||
import com.food.order.system.saga.SagaStep;
|
|
||||||
import com.food.order.sysyem.dto.message.RestaurantApprovalResponse;
|
|
||||||
import com.food.order.sysyem.helper.OrderSagaHelper;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class OrderApprovalSaga implements SagaStep<RestaurantApprovalResponse> {
|
|
||||||
|
|
||||||
private final OrderDomainService orderDomainService;
|
|
||||||
private final OrderSagaHelper orderSagaHelper;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void process(RestaurantApprovalResponse data) {
|
|
||||||
log.info("Approving order with id: {}", data.getOrderId());
|
|
||||||
var order = orderSagaHelper.findOrder(data.getOrderId());
|
|
||||||
orderDomainService.approve(order);
|
|
||||||
orderSagaHelper.saveOrder(order);
|
|
||||||
log.info("Order approved: {}", order);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void rollback(RestaurantApprovalResponse data) {
|
|
||||||
log.info("Approving order with id: {}", data.getOrderId());
|
|
||||||
var order = orderSagaHelper.findOrder(data.getOrderId());
|
|
||||||
var cancelEvent = orderDomainService.cancelOrderPayment
|
|
||||||
(order,
|
|
||||||
data.getFailureMessages());
|
|
||||||
orderSagaHelper.saveOrder(order);
|
|
||||||
log.info("Order cancelled: {}", order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
package com.food.order.sysyem.saga;
|
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Order;
|
|
||||||
import com.food.order.system.domain.event.OrderPaidEvent;
|
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
|
||||||
import com.food.order.system.domain.service.OrderDomainService;
|
|
||||||
import com.food.order.system.outbox.OutboxStatus;
|
|
||||||
import com.food.order.system.saga.SagaStatus;
|
|
||||||
import com.food.order.system.saga.SagaStep;
|
|
||||||
import com.food.order.sysyem.dto.message.PaymentResponse;
|
|
||||||
import com.food.order.sysyem.helper.OrderSagaHelper;
|
|
||||||
import com.food.order.sysyem.mapper.OrderDataMapper;
|
|
||||||
import com.food.order.sysyem.outbox.model.approval.OrderApprovalOutboxMessage;
|
|
||||||
import com.food.order.sysyem.outbox.model.payment.OrderPaymentOutboxMessage;
|
|
||||||
import com.food.order.sysyem.outbox.scheduler.approval.ApprovalOutboxHelper;
|
|
||||||
import com.food.order.sysyem.outbox.scheduler.payment.PaymentOutboxHelper;
|
|
||||||
import com.food.order.sysyem.valueobject.OrderStatus;
|
|
||||||
import com.food.order.sysyem.valueobject.PaymentStatus;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.ZonedDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static com.food.order.sysyem.DomainConstants.UTC;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class OrderPaymentSaga implements SagaStep<PaymentResponse> {
|
|
||||||
|
|
||||||
private final OrderDomainService orderDomainService;
|
|
||||||
private final OrderSagaHelper orderSagaHelper;
|
|
||||||
private final OrderDataMapper orderDataMapper;
|
|
||||||
private final ApprovalOutboxHelper approvalOutboxHelper;
|
|
||||||
private final PaymentOutboxHelper paymentOutboxHelper;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void process(PaymentResponse data) {
|
|
||||||
|
|
||||||
var messageResponse =
|
|
||||||
paymentOutboxHelper.getPaymentOutboxMessageBySagaIdAndSagaStatus(
|
|
||||||
UUID.fromString(data.getSagaId()),
|
|
||||||
SagaStatus.STARTED)
|
|
||||||
.orElseThrow(() -> {
|
|
||||||
log.error("Payment outbox message not found for saga id: {}", data.getSagaId());
|
|
||||||
return new OrderDomainException("Payment outbox message not found for saga id: " + data.getSagaId());
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var paidEvent = completePaymentForOrder(data);
|
|
||||||
|
|
||||||
var sagaStatus = orderSagaHelper.orderStatusToSagaStatus(paidEvent.getOrder().getStatus());
|
|
||||||
|
|
||||||
paymentOutboxHelper.save(getUpdatedPaymentOutboxMessage(messageResponse,
|
|
||||||
paidEvent.getOrder().getStatus(),
|
|
||||||
sagaStatus));
|
|
||||||
|
|
||||||
approvalOutboxHelper.saveApprovalOutboxMessage(
|
|
||||||
orderDataMapper.orderPaidEventToOrderApprovalEventPayload(paidEvent),
|
|
||||||
paidEvent.getOrder().getStatus(),
|
|
||||||
sagaStatus,
|
|
||||||
OutboxStatus.STARTED,
|
|
||||||
messageResponse.getSagaId()
|
|
||||||
);
|
|
||||||
|
|
||||||
log.info("Payment completed for order with id: {}", paidEvent.getOrder().getId().getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
private OrderPaymentOutboxMessage getUpdatedPaymentOutboxMessage(OrderPaymentOutboxMessage messageResponse,
|
|
||||||
OrderStatus status,
|
|
||||||
SagaStatus sagaStatus) {
|
|
||||||
messageResponse.setProcessedAt(ZonedDateTime.now(ZoneId.of(UTC)));
|
|
||||||
messageResponse.setOrderStatus(status);
|
|
||||||
messageResponse.setSagaStatus(sagaStatus);
|
|
||||||
return messageResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Transactional
|
|
||||||
public void rollback(PaymentResponse data) {
|
|
||||||
|
|
||||||
var messageResponse =
|
|
||||||
paymentOutboxHelper.getPaymentOutboxMessageBySagaIdAndSagaStatus(
|
|
||||||
UUID.fromString(data.getSagaId()),
|
|
||||||
getCurrentSagaStatus(data.getPaymentStatus()))
|
|
||||||
.orElseThrow(
|
|
||||||
() -> {
|
|
||||||
log.error("Payment outbox message not found for saga id: {}", data.getSagaId());
|
|
||||||
return new OrderDomainException("Payment outbox message not found for saga id: " + data.getSagaId());
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
var orderRollback = rollbackPaymentForOrder(data);
|
|
||||||
|
|
||||||
var sagaStatus = orderSagaHelper.orderStatusToSagaStatus(orderRollback.getStatus());
|
|
||||||
|
|
||||||
paymentOutboxHelper.save(getUpdatedPaymentOutboxMessage(messageResponse,
|
|
||||||
orderRollback.getStatus(),
|
|
||||||
sagaStatus));
|
|
||||||
|
|
||||||
if (data.getPaymentStatus().equals(PaymentStatus.CANCELED)) {
|
|
||||||
approvalOutboxHelper.save(getUpdatedApprovalOutboxMessage(data.getSagaId(),
|
|
||||||
orderRollback.getStatus(),
|
|
||||||
sagaStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("Payment rolled back for order with id: {}", orderRollback.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private OrderApprovalOutboxMessage getUpdatedApprovalOutboxMessage(String sagaId,
|
|
||||||
OrderStatus orderStatus,
|
|
||||||
SagaStatus sagaStatus) {
|
|
||||||
var orderApprovalOutboxMessageResponse =
|
|
||||||
approvalOutboxHelper.getApprovalOutboxMessageBySagaIdAndSagaStatus(
|
|
||||||
UUID.fromString(sagaId),
|
|
||||||
SagaStatus.COMPENSATING);
|
|
||||||
if (orderApprovalOutboxMessageResponse.isEmpty()) {
|
|
||||||
throw new OrderDomainException("Approval outbox message could not be found in " +
|
|
||||||
SagaStatus.COMPENSATING.name() + " status!");
|
|
||||||
}
|
|
||||||
var orderApprovalOutboxMessage = orderApprovalOutboxMessageResponse.get();
|
|
||||||
orderApprovalOutboxMessage.setProcessedAt(ZonedDateTime.now(ZoneId.of(UTC)));
|
|
||||||
orderApprovalOutboxMessage.setOrderStatus(orderStatus);
|
|
||||||
orderApprovalOutboxMessage.setSagaStatus(sagaStatus);
|
|
||||||
return orderApprovalOutboxMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Order rollbackPaymentForOrder(PaymentResponse paymentResponse) {
|
|
||||||
log.info("Cancelling order with id: {}", paymentResponse.getOrderId());
|
|
||||||
var order = orderSagaHelper.findOrder(paymentResponse.getOrderId());
|
|
||||||
orderDomainService.cancelOrder(order, paymentResponse.getFailureMessages());
|
|
||||||
orderSagaHelper.saveOrder(order);
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SagaStatus[] getCurrentSagaStatus(PaymentStatus paymentStatus) {
|
|
||||||
return switch (paymentStatus) {
|
|
||||||
case COMPLETED -> new SagaStatus[]{SagaStatus.STARTED};
|
|
||||||
case CANCELED -> new SagaStatus[]{SagaStatus.PROCESSING};
|
|
||||||
case FAILED -> new SagaStatus[]{SagaStatus.STARTED, SagaStatus.PROCESSING};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private OrderPaidEvent completePaymentForOrder(PaymentResponse data) {
|
|
||||||
var order = orderSagaHelper.findOrder(data.getOrderId());
|
|
||||||
var paidEvent = orderDomainService.payOrder(order);
|
|
||||||
orderSagaHelper.saveOrder(order);
|
|
||||||
log.info("Payment completed for order with id: {}", order.getId());
|
|
||||||
return paidEvent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,237 @@
|
|||||||
|
package com.food.order.system;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.food.order.system.domain.entity.Customer;
|
||||||
|
import com.food.order.system.domain.entity.Order;
|
||||||
|
import com.food.order.system.domain.entity.Product;
|
||||||
|
import com.food.order.system.domain.entity.Restaurant;
|
||||||
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
|
import com.food.order.system.dto.create.CreateOrderCommand;
|
||||||
|
import com.food.order.system.dto.create.CreateOrderResponse;
|
||||||
|
import com.food.order.system.dto.create.OrderAddress;
|
||||||
|
import com.food.order.system.dto.create.OrderItem;
|
||||||
|
import com.food.order.system.mapper.OrderDataMapper;
|
||||||
|
import com.food.order.system.outbox.OutboxStatus;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentEventPayload;
|
||||||
|
import com.food.order.system.outbox.model.payment.OrderPaymentOutboxMessage;
|
||||||
|
import com.food.order.system.ports.input.service.OrderApplicationService;
|
||||||
|
import com.food.order.system.ports.output.repository.CustomerRepository;
|
||||||
|
import com.food.order.system.ports.output.repository.OrderRepository;
|
||||||
|
import com.food.order.system.ports.output.repository.PaymentOutboxRepository;
|
||||||
|
import com.food.order.system.ports.output.repository.RestaurantRepository;
|
||||||
|
import com.food.order.system.saga.SagaStatus;
|
||||||
|
import com.food.order.system.valueobject.*;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestInstance;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static com.food.order.system.outbox.order.SagaConst.ORDER_PROCESSING_SAGA;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
@SpringBootTest(classes = OrderTestConfiguration.class)
|
||||||
|
class OrderApplicationServiceTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderApplicationService orderApplicationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderDataMapper orderDataMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderRepository orderRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CustomerRepository customerRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RestaurantRepository restaurantRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PaymentOutboxRepository paymentOutboxRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
private CreateOrderCommand createOrderCommand;
|
||||||
|
private CreateOrderCommand createOrderCommandWrongPrice;
|
||||||
|
private CreateOrderCommand createOrderCommandWrongProductPrice;
|
||||||
|
private final UUID CUSTOMER_ID = UUID.fromString("d215b5f8-0249-4dc5-89a3-51fd148cfb41");
|
||||||
|
private final UUID RESTAURANT_ID = UUID.fromString("d215b5f8-0249-4dc5-89a3-51fd148cfb45");
|
||||||
|
private final UUID PRODUCT_ID = UUID.fromString("d215b5f8-0249-4dc5-89a3-51fd148cfb48");
|
||||||
|
private final UUID ORDER_ID = UUID.fromString("15a497c1-0f4b-4eff-b9f4-c402c8c07afb");
|
||||||
|
private final UUID SAGA_ID = UUID.fromString("15a497c1-0f4b-4eff-b9f4-c402c8c07afa");
|
||||||
|
private final BigDecimal PRICE = new BigDecimal("200.00");
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
public void init() {
|
||||||
|
createOrderCommand = CreateOrderCommand.builder()
|
||||||
|
.customerId(CUSTOMER_ID)
|
||||||
|
.restaurantId(RESTAURANT_ID)
|
||||||
|
.orderAddress(OrderAddress.builder()
|
||||||
|
.street("street_1")
|
||||||
|
.postalCode("1000AB")
|
||||||
|
.city("Paris")
|
||||||
|
.build())
|
||||||
|
.price(PRICE)
|
||||||
|
.orderItems(List.of(OrderItem.builder()
|
||||||
|
.productId(PRODUCT_ID)
|
||||||
|
.quantity(1)
|
||||||
|
.price(new BigDecimal("50.00"))
|
||||||
|
.subTotal(new BigDecimal("50.00"))
|
||||||
|
.build(),
|
||||||
|
OrderItem.builder()
|
||||||
|
.productId(PRODUCT_ID)
|
||||||
|
.quantity(3)
|
||||||
|
.price(new BigDecimal("50.00"))
|
||||||
|
.subTotal(new BigDecimal("150.00"))
|
||||||
|
.build()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
createOrderCommandWrongPrice = CreateOrderCommand.builder()
|
||||||
|
.customerId(CUSTOMER_ID)
|
||||||
|
.restaurantId(RESTAURANT_ID)
|
||||||
|
.orderAddress(OrderAddress.builder()
|
||||||
|
.street("street_1")
|
||||||
|
.postalCode("1000AB")
|
||||||
|
.city("Paris")
|
||||||
|
.build())
|
||||||
|
.price(new BigDecimal("250.00"))
|
||||||
|
.orderItems(List.of(OrderItem.builder()
|
||||||
|
.productId(PRODUCT_ID)
|
||||||
|
.quantity(1)
|
||||||
|
.price(new BigDecimal("50.00"))
|
||||||
|
.subTotal(new BigDecimal("50.00"))
|
||||||
|
.build(),
|
||||||
|
OrderItem.builder()
|
||||||
|
.productId(PRODUCT_ID)
|
||||||
|
.quantity(3)
|
||||||
|
.price(new BigDecimal("50.00"))
|
||||||
|
.subTotal(new BigDecimal("150.00"))
|
||||||
|
.build()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
createOrderCommandWrongProductPrice = CreateOrderCommand.builder()
|
||||||
|
.customerId(CUSTOMER_ID)
|
||||||
|
.restaurantId(RESTAURANT_ID)
|
||||||
|
.orderAddress(OrderAddress.builder()
|
||||||
|
.street("street_1")
|
||||||
|
.postalCode("1000AB")
|
||||||
|
.city("Paris")
|
||||||
|
.build())
|
||||||
|
.price(new BigDecimal("210.00"))
|
||||||
|
.orderItems(List.of(OrderItem.builder()
|
||||||
|
.productId(PRODUCT_ID)
|
||||||
|
.quantity(1)
|
||||||
|
.price(new BigDecimal("60.00"))
|
||||||
|
.subTotal(new BigDecimal("60.00"))
|
||||||
|
.build(),
|
||||||
|
OrderItem.builder()
|
||||||
|
.productId(PRODUCT_ID)
|
||||||
|
.quantity(3)
|
||||||
|
.price(new BigDecimal("50.00"))
|
||||||
|
.subTotal(new BigDecimal("150.00"))
|
||||||
|
.build()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Customer customer = new Customer(new CustomerId(CUSTOMER_ID));
|
||||||
|
|
||||||
|
Restaurant restaurantResponse = Restaurant.builder()
|
||||||
|
.id(new RestaurantId(createOrderCommand.restaurantId()))
|
||||||
|
.products(List.of(new Product(new ProductId(PRODUCT_ID), "product-1", new Money(new BigDecimal("50.00"))),
|
||||||
|
new Product(new ProductId(PRODUCT_ID), "product-2", new Money(new BigDecimal("50.00")))))
|
||||||
|
.isActive(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Order order = orderDataMapper.createOrderCommandToOrder(createOrderCommand);
|
||||||
|
order.setId(new OrderId(ORDER_ID));
|
||||||
|
|
||||||
|
when(customerRepository.findCustomer(CUSTOMER_ID)).thenReturn(Optional.of(customer));
|
||||||
|
when(restaurantRepository.findRestaurantInformation(orderDataMapper.createOrderCommandToRestaurant(createOrderCommand)))
|
||||||
|
.thenReturn(Optional.of(restaurantResponse));
|
||||||
|
when(orderRepository.save(any(Order.class))).thenReturn(order);
|
||||||
|
when(paymentOutboxRepository.save(any(OrderPaymentOutboxMessage.class))).thenReturn(getOrderPaymentOutboxMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateOrder() {
|
||||||
|
CreateOrderResponse createOrderResponse = orderApplicationService.createOrder(createOrderCommand);
|
||||||
|
assertEquals(OrderStatus.PENDING, createOrderResponse.orderStatus());
|
||||||
|
assertEquals("Order created successfully", createOrderResponse.message());
|
||||||
|
assertNotNull(createOrderResponse.orderTrackingId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateOrderWithWrongTotalPrice() {
|
||||||
|
OrderDomainException orderDomainException = assertThrows(OrderDomainException.class,
|
||||||
|
() -> orderApplicationService.createOrder(createOrderCommandWrongPrice));
|
||||||
|
assertEquals("Order total price is not equal to the sum of order items prices",
|
||||||
|
orderDomainException.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateOrderWithWrongProductPrice() {
|
||||||
|
OrderDomainException orderDomainException = assertThrows(OrderDomainException.class,
|
||||||
|
() -> orderApplicationService.createOrder(createOrderCommandWrongProductPrice));
|
||||||
|
assertEquals(orderDomainException.getMessage(),
|
||||||
|
"Order item price is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateOrderWithPassiveRestaurant() {
|
||||||
|
Restaurant restaurantResponse = Restaurant.builder()
|
||||||
|
.id(new RestaurantId(createOrderCommand.restaurantId()))
|
||||||
|
.products(List.of(new Product(new ProductId(PRODUCT_ID), "product-1", new Money(new BigDecimal("50.00"))),
|
||||||
|
new Product(new ProductId(PRODUCT_ID), "product-2", new Money(new BigDecimal("50.00")))))
|
||||||
|
.isActive(false)
|
||||||
|
.build();
|
||||||
|
when(restaurantRepository.findRestaurantInformation(orderDataMapper.createOrderCommandToRestaurant(createOrderCommand)))
|
||||||
|
.thenReturn(Optional.of(restaurantResponse));
|
||||||
|
OrderDomainException orderDomainException = assertThrows(OrderDomainException.class,
|
||||||
|
() -> orderApplicationService.createOrder(createOrderCommand));
|
||||||
|
assertEquals(orderDomainException.getMessage(),
|
||||||
|
"Restaurant is not active, please try again later. Restaurant id: " + restaurantResponse.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderPaymentOutboxMessage getOrderPaymentOutboxMessage() {
|
||||||
|
OrderPaymentEventPayload orderPaymentEventPayload = OrderPaymentEventPayload.builder()
|
||||||
|
.orderId(ORDER_ID.toString())
|
||||||
|
.customerId(CUSTOMER_ID.toString())
|
||||||
|
.price(PRICE)
|
||||||
|
.createdAt(ZonedDateTime.now())
|
||||||
|
.paymentOrderStatus(PaymentOrderStatus.PENDING.name())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return OrderPaymentOutboxMessage.builder()
|
||||||
|
.id(UUID.randomUUID())
|
||||||
|
.sagaId(SAGA_ID)
|
||||||
|
.createdAt(ZonedDateTime.now())
|
||||||
|
.type(ORDER_PROCESSING_SAGA)
|
||||||
|
.payload(createPayload(orderPaymentEventPayload))
|
||||||
|
.orderStatus(OrderStatus.PENDING)
|
||||||
|
.sagaStatus(SagaStatus.STARTED)
|
||||||
|
.outboxStatus(OutboxStatus.STARTED)
|
||||||
|
.version(0)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String createPayload(OrderPaymentEventPayload orderPaymentEventPayload) {
|
||||||
|
try {
|
||||||
|
return objectMapper.writeValueAsString(orderPaymentEventPayload);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new OrderDomainException("Cannot create OrderPaymentEventPayload object!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.food.order.system;
|
||||||
|
|
||||||
|
import com.food.order.system.domain.service.OrderDomainService;
|
||||||
|
import com.food.order.system.domain.service.impl.OrderDomainServiceImpl;
|
||||||
|
import com.food.order.system.ports.output.message.publisher.payment.PaymentRequestMessagePublisher;
|
||||||
|
import com.food.order.system.ports.output.message.publisher.restaurantapproval.RestaurantApprovalRequestMessagePublisher;
|
||||||
|
import com.food.order.system.ports.output.repository.*;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
@SpringBootApplication(scanBasePackages = "com.food.order")
|
||||||
|
public class OrderTestConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PaymentRequestMessagePublisher paymentRequestMessagePublisher() {
|
||||||
|
return Mockito.mock(PaymentRequestMessagePublisher.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestaurantApprovalRequestMessagePublisher restaurantApprovalRequestMessagePublisher() {
|
||||||
|
return Mockito.mock(RestaurantApprovalRequestMessagePublisher.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public OrderRepository orderRepository() {
|
||||||
|
return Mockito.mock(OrderRepository.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CustomerRepository customerRepository() {
|
||||||
|
return Mockito.mock(CustomerRepository.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestaurantRepository restaurantRepository() {
|
||||||
|
return Mockito.mock(RestaurantRepository.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PaymentOutboxRepository paymentOutboxRepository() {
|
||||||
|
return Mockito.mock(PaymentOutboxRepository.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ApprovalOutboxRepository approvalOutboxRepository() {
|
||||||
|
return Mockito.mock(ApprovalOutboxRepository.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public OrderDomainService orderDomainService() {
|
||||||
|
return new OrderDomainServiceImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
order-service:
|
||||||
|
outbox-scheduler-fixed-rate: 10000
|
||||||
|
outbox-scheduler-initial-delay: 10000
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.food.order.system.domain.entity;
|
package com.food.order.system.domain.entity;
|
||||||
|
|
||||||
import com.food.order.sysyem.entity.AggregateRoot;
|
import com.food.order.system.entity.AggregateRoot;
|
||||||
import com.food.order.sysyem.valueobject.CustomerId;
|
import com.food.order.system.valueobject.CustomerId;
|
||||||
|
|
||||||
public class Customer extends AggregateRoot<CustomerId> {
|
public class Customer extends AggregateRoot<CustomerId> {
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.food.order.system.domain.entity;
|
package com.food.order.system.domain.entity;
|
||||||
|
|
||||||
import com.food.order.sysyem.entity.AggregateRoot;
|
import com.food.order.system.entity.AggregateRoot;
|
||||||
import com.food.order.system.domain.exception.OrderDomainException;
|
import com.food.order.system.domain.exception.OrderDomainException;
|
||||||
import com.food.order.system.domain.valueobject.OrderItemId;
|
import com.food.order.system.domain.valueobject.OrderItemId;
|
||||||
import com.food.order.system.domain.valueobject.StreetAddress;
|
import com.food.order.system.domain.valueobject.StreetAddress;
|
||||||
import com.food.order.system.domain.valueobject.TrackingId;
|
import com.food.order.system.domain.valueobject.TrackingId;
|
||||||
import com.food.order.sysyem.valueobject.*;
|
import com.food.order.system.valueobject.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.system.domain.entity;
|
package com.food.order.system.domain.entity;
|
||||||
|
|
||||||
import com.food.order.sysyem.entity.BaseEntity;
|
import com.food.order.system.entity.BaseEntity;
|
||||||
import com.food.order.sysyem.valueobject.Money;
|
import com.food.order.system.valueobject.Money;
|
||||||
import com.food.order.sysyem.valueobject.OrderId;
|
import com.food.order.system.valueobject.OrderId;
|
||||||
import com.food.order.system.domain.valueobject.OrderItemId;
|
import com.food.order.system.domain.valueobject.OrderItemId;
|
||||||
|
|
||||||
public class OrderItem extends BaseEntity<OrderItemId> {
|
public class OrderItem extends BaseEntity<OrderItemId> {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.food.order.system.domain.entity;
|
package com.food.order.system.domain.entity;
|
||||||
|
|
||||||
import com.food.order.sysyem.entity.BaseEntity;
|
import com.food.order.system.entity.BaseEntity;
|
||||||
import com.food.order.sysyem.valueobject.Money;
|
import com.food.order.system.valueobject.Money;
|
||||||
import com.food.order.sysyem.valueobject.ProductId;
|
import com.food.order.system.valueobject.ProductId;
|
||||||
|
|
||||||
public class Product extends BaseEntity<ProductId> {
|
public class Product extends BaseEntity<ProductId> {
|
||||||
private String name;
|
private String name;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.food.order.system.domain.entity;
|
package com.food.order.system.domain.entity;
|
||||||
|
|
||||||
import com.food.order.sysyem.entity.AggregateRoot;
|
import com.food.order.system.entity.AggregateRoot;
|
||||||
import com.food.order.sysyem.valueobject.RestaurantId;
|
import com.food.order.system.valueobject.RestaurantId;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.food.order.system.domain.event;
|
package com.food.order.system.domain.event;
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
import com.food.order.sysyem.event.publisher.DomainEventPublisher;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.domain.event;
|
package com.food.order.system.domain.event;
|
||||||
|
|
||||||
import com.food.order.sysyem.event.DomainEvent;
|
import com.food.order.system.event.DomainEvent;
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.food.order.system.domain.event;
|
package com.food.order.system.domain.event;
|
||||||
|
|
||||||
import com.food.order.system.domain.entity.Order;
|
import com.food.order.system.domain.entity.Order;
|
||||||
import com.food.order.sysyem.event.publisher.DomainEventPublisher;
|
|
||||||
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.domain.exception;
|
package com.food.order.system.domain.exception;
|
||||||
|
|
||||||
import com.food.order.sysyem.exception.DomainException;
|
import com.food.order.system.exception.DomainException;
|
||||||
|
|
||||||
public class OrderDomainException extends DomainException {
|
public class OrderDomainException extends DomainException {
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.domain.exception;
|
package com.food.order.system.domain.exception;
|
||||||
|
|
||||||
import com.food.order.sysyem.exception.DomainException;
|
import com.food.order.system.exception.DomainException;
|
||||||
|
|
||||||
public class OrderNotFoundException extends DomainException {
|
public class OrderNotFoundException extends DomainException {
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.domain.valueobject;
|
package com.food.order.system.domain.valueobject;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.BaseId;
|
import com.food.order.system.valueobject.BaseId;
|
||||||
|
|
||||||
public class OrderItemId extends BaseId<Long> {
|
public class OrderItemId extends BaseId<Long> {
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.food.order.system.domain.valueobject;
|
package com.food.order.system.domain.valueobject;
|
||||||
|
|
||||||
import com.food.order.sysyem.valueobject.BaseId;
|
import com.food.order.system.valueobject.BaseId;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.food.order.system.order.messaging.listener.kafka;
|
package com.food.order.system.messaging.listener.kafka;
|
||||||
|
|
||||||
import com.food.order.system.kafka.consumer.KafkaConsumer;
|
import com.food.order.system.kafka.consumer.KafkaConsumer;
|
||||||
import com.food.order.system.kafka.order.avro.model.PaymentResponseAvroModel;
|
import com.food.order.system.kafka.order.avro.model.PaymentResponseAvroModel;
|
||||||
import com.food.order.system.kafka.order.avro.model.PaymentStatus;
|
import com.food.order.system.kafka.order.avro.model.PaymentStatus;
|
||||||
import com.food.order.system.order.messaging.mapper.OrderMessagingDataMapper;
|
import com.food.order.system.messaging.mapper.OrderMessagingDataMapper;
|
||||||
import com.food.order.sysyem.ports.input.message.listener.payment.PaymentResponseMessageListener;
|
import com.food.order.system.ports.input.message.listener.payment.PaymentResponseMessageListener;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.kafka.annotation.KafkaListener;
|
import org.springframework.kafka.annotation.KafkaListener;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.food.order.system.order.messaging.listener.kafka;
|
package com.food.order.system.messaging.listener.kafka;
|
||||||
|
|
||||||
import com.food.order.system.kafka.consumer.KafkaConsumer;
|
import com.food.order.system.kafka.consumer.KafkaConsumer;
|
||||||
import com.food.order.system.kafka.order.avro.model.OrderApprovalStatus;
|
import com.food.order.system.kafka.order.avro.model.OrderApprovalStatus;
|
||||||
import com.food.order.system.kafka.order.avro.model.RestaurantApprovalResponseAvroModel;
|
import com.food.order.system.kafka.order.avro.model.RestaurantApprovalResponseAvroModel;
|
||||||
import com.food.order.system.order.messaging.mapper.OrderMessagingDataMapper;
|
import com.food.order.system.messaging.mapper.OrderMessagingDataMapper;
|
||||||
import com.food.order.sysyem.ports.input.message.listener.restaurantapproval.RestaurantApprovalResponseMessageListener;
|
import com.food.order.system.ports.input.message.listener.restaurantapproval.RestaurantApprovalResponseMessageListener;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.kafka.annotation.KafkaListener;
|
import org.springframework.kafka.annotation.KafkaListener;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user