Add Domain Core Classes And Common Domain Module.
This commit is contained in:
31
README.md
Normal file
31
README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
<p align="center">
|
||||
<img src="img/diagram.png" alt="ci" width="1000" class="center"/>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
# What we are doing here ?
|
||||
|
||||
- Hexagonal (Clean) Architecture -> Port & Adapter Style
|
||||
|
||||
- Domain Driven Desing (DDD)
|
||||
|
||||
- SAGA Pattern : process & rollback ( compensating transactions )
|
||||
|
||||
- Outbox Pattern : Pulling Outbox Table With Scheduler , Saga Status
|
||||
|
||||
- Cover Failure Scerinarios :
|
||||
|
||||
- Ensure idempotency using outbox table in each service
|
||||
|
||||
- Prevent concurrency issues with optimistic looks & DB constaints
|
||||
|
||||
- Kepp updating saga and order status for each operation
|
||||
|
||||
- CQRS Pattern : Materialized view & Event Sourcing
|
||||
|
||||
- Relational Database : for ACID and distributed transactional
|
||||
|
||||
- Kafka Messaging Systems for CQRS desing and Microservices Communication
|
||||
|
||||
- Kubernetes And GKE ( Google Kubernetes Engine )
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.food.order.domain.exception;
|
||||
|
||||
public class DomainException extends RuntimeException {
|
||||
|
||||
public DomainException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DomainException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ public class Money {
|
||||
|
||||
private final BigDecimal amount;
|
||||
|
||||
public static final Money ZERO = new Money(BigDecimal.ZERO);
|
||||
|
||||
public Money(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.food.order.system.domain.entity;
|
||||
|
||||
import com.food.order.domain.entity.AggregateRoot;
|
||||
import com.food.order.domain.valueobject.CustomerId;
|
||||
|
||||
public class Customer extends AggregateRoot<CustomerId> {
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package com.food.order.system.domain.entity;
|
||||
|
||||
import com.food.order.domain.entity.AggregateRoot;
|
||||
import com.food.order.domain.valueobject.*;
|
||||
import com.food.order.system.domain.exception.OrderDomainException;
|
||||
import com.food.order.system.domain.valueobject.OrderItemId;
|
||||
import com.food.order.system.domain.valueobject.StreetAddress;
|
||||
import com.food.order.system.domain.valueobject.TrackingId;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Order extends AggregateRoot<OrderId> {
|
||||
|
||||
private final CustomerId customerId;
|
||||
private final RestaurantId restaurantId;
|
||||
private final StreetAddress deliveryAddress;
|
||||
private final Money price;
|
||||
private final List<OrderItem> items;
|
||||
|
||||
private TrackingId trackingId;
|
||||
private OrderStatus status;
|
||||
private List<String> failureMessages;
|
||||
|
||||
public void initializeOrder(){
|
||||
setId(new OrderId(UUID.randomUUID()));
|
||||
trackingId = new TrackingId(UUID.randomUUID());
|
||||
status = OrderStatus.PENDING;
|
||||
initializeOrderItems();
|
||||
}
|
||||
|
||||
public void pay(){
|
||||
if(!Objects.equals(status, OrderStatus.PENDING))
|
||||
throw new OrderDomainException("Order status is not pending !");
|
||||
status = OrderStatus.PAID;
|
||||
|
||||
}
|
||||
|
||||
public void approve(){
|
||||
if(!Objects.equals(status, OrderStatus.PAID))
|
||||
throw new OrderDomainException("Order status is not paid !");
|
||||
status = OrderStatus.APPROVED;
|
||||
}
|
||||
|
||||
public void initCancel(List<String> failureMessages){
|
||||
if(!Objects.equals(status, OrderStatus.PAID))
|
||||
throw new OrderDomainException("Order status is not correct for initCancel operation !");
|
||||
status = OrderStatus.CANCELLED;
|
||||
updateFailureMessages(failureMessages);
|
||||
}
|
||||
|
||||
public void cancel(List<String> failureMessages){
|
||||
if(Objects.equals(status, OrderStatus.CANCELLING) || Objects.equals(status, OrderStatus.PENDING))
|
||||
throw new OrderDomainException("Order status is not correct for cancel operation !");
|
||||
status = OrderStatus.CANCELLED;
|
||||
updateFailureMessages(failureMessages);
|
||||
}
|
||||
|
||||
private void updateFailureMessages(List<String> failureMessages) {
|
||||
if (Objects.nonNull(this.failureMessages) && Objects.nonNull(failureMessages)) {
|
||||
this.failureMessages.addAll(failureMessages.stream().filter(Objects::nonNull).toList());
|
||||
} else {
|
||||
this.failureMessages = failureMessages;
|
||||
}
|
||||
}
|
||||
|
||||
public void validateOrder(){
|
||||
validateInitialOrder();
|
||||
validateTotalPrice();
|
||||
validateItemsPrice();
|
||||
}
|
||||
|
||||
private void validateItemsPrice() {
|
||||
Money orderItemsTotal = items
|
||||
.stream()
|
||||
.map(orderItem -> {
|
||||
validateItemPrice(orderItem);
|
||||
return orderItem.getSubTotal();
|
||||
})
|
||||
.reduce(Money.ZERO, Money::add);
|
||||
|
||||
if(!Objects.equals(orderItemsTotal, price)){
|
||||
throw new OrderDomainException("Order total price is not equal to the sum of order items prices");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateItemPrice(OrderItem orderItem) {
|
||||
if(!orderItem.isPriceValid()){
|
||||
throw new OrderDomainException("Order item price is not valid");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateTotalPrice() {
|
||||
if(Objects.nonNull(price) && !price.isGreaterThanZero()){
|
||||
throw new OrderDomainException("Total price cannot be less than zero");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateInitialOrder() {
|
||||
if (Objects.nonNull(status) && Objects.nonNull(getId()))
|
||||
throw new OrderDomainException("Order is not in correct state to be initialized");
|
||||
|
||||
}
|
||||
|
||||
private void initializeOrderItems() {
|
||||
long itemId = 1;
|
||||
for (OrderItem item : items) {
|
||||
item.initializeOrderItem(super.getId(), new OrderItemId(itemId++));
|
||||
}
|
||||
}
|
||||
|
||||
private Order(Builder builder) {
|
||||
super.setId(builder.orderId);
|
||||
customerId = builder.customerId;
|
||||
restaurantId = builder.restaurantId;
|
||||
deliveryAddress = builder.deliveryAddress;
|
||||
price = builder.price;
|
||||
items = builder.items;
|
||||
trackingId = builder.trackingId;
|
||||
status = builder.status;
|
||||
failureMessages = builder.failureMessages;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public CustomerId getCustomerId() {
|
||||
return customerId;
|
||||
}
|
||||
|
||||
public RestaurantId getRestaurantId() {
|
||||
return restaurantId;
|
||||
}
|
||||
|
||||
public StreetAddress getDeliveryAddress() {
|
||||
return deliveryAddress;
|
||||
}
|
||||
|
||||
public Money getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public List<OrderItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public TrackingId getTrackingId() {
|
||||
return trackingId;
|
||||
}
|
||||
|
||||
public OrderStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public List<String> getFailureMessages() {
|
||||
return failureMessages;
|
||||
}
|
||||
|
||||
|
||||
public static final class Builder {
|
||||
private OrderId orderId;
|
||||
private CustomerId customerId;
|
||||
private RestaurantId restaurantId;
|
||||
private StreetAddress deliveryAddress;
|
||||
private Money price;
|
||||
private List<OrderItem> items;
|
||||
private TrackingId trackingId;
|
||||
private OrderStatus status;
|
||||
private List<String> failureMessages;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder orderId(OrderId val) {
|
||||
orderId = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder customerId(CustomerId val) {
|
||||
customerId = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder restaurantId(RestaurantId val) {
|
||||
restaurantId = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder deliveryAddress(StreetAddress val) {
|
||||
deliveryAddress = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder price(Money val) {
|
||||
price = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder items(List<OrderItem> val) {
|
||||
items = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder trackingId(TrackingId val) {
|
||||
trackingId = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder status(OrderStatus val) {
|
||||
status = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder failureMessages(List<String> val) {
|
||||
failureMessages = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Order build() {
|
||||
return new Order(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.food.order.system.domain.entity;
|
||||
|
||||
import com.food.order.domain.entity.BaseEntity;
|
||||
import com.food.order.domain.valueobject.Money;
|
||||
import com.food.order.domain.valueobject.OrderId;
|
||||
import com.food.order.system.domain.valueobject.OrderItemId;
|
||||
|
||||
public class OrderItem extends BaseEntity<OrderItemId> {
|
||||
|
||||
private OrderId orderId;
|
||||
private final Product product;
|
||||
private final int quantity;
|
||||
private final Money price;
|
||||
private final Money subTotal;
|
||||
|
||||
void initializeOrderItem(OrderId orderId, OrderItemId orderItemId) {
|
||||
this.orderId = orderId;
|
||||
super.setId(orderItemId);
|
||||
}
|
||||
|
||||
boolean isPriceValid() {
|
||||
return price.isGreaterThanZero() &&
|
||||
price.equals(product.getPrice()) &&
|
||||
price.multiply(quantity).equals(subTotal);
|
||||
}
|
||||
|
||||
private OrderItem(Builder builder) {
|
||||
super.setId(builder.orderItemId);
|
||||
product = builder.product;
|
||||
quantity = builder.quantity;
|
||||
price = builder.price;
|
||||
subTotal = builder.subTotal;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public OrderId getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
|
||||
public Product getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public Money getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public Money getSubTotal() {
|
||||
return subTotal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static final class Builder {
|
||||
private OrderItemId orderItemId;
|
||||
private Product product;
|
||||
private int quantity;
|
||||
private Money price;
|
||||
private Money subTotal;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder orderItemId(OrderItemId val) {
|
||||
orderItemId = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder product(Product val) {
|
||||
product = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder quantity(int val) {
|
||||
quantity = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder price(Money val) {
|
||||
price = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder subTotal(Money val) {
|
||||
subTotal = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OrderItem build() {
|
||||
return new OrderItem(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.food.order.system.domain.entity;
|
||||
|
||||
import com.food.order.domain.entity.BaseEntity;
|
||||
import com.food.order.domain.valueobject.Money;
|
||||
import com.food.order.domain.valueobject.ProductId;
|
||||
|
||||
public class Product extends BaseEntity<ProductId> {
|
||||
private String name;
|
||||
private Money price;
|
||||
|
||||
public Product(ProductId id, String name, Money price) {
|
||||
super.setId(id);
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Money getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void updateWithConfirmedNameAndPrice(String name, Money price) {
|
||||
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.food.order.system.domain.entity;
|
||||
|
||||
import com.food.order.domain.entity.AggregateRoot;
|
||||
import com.food.order.domain.valueobject.RestaurantId;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Restaurant extends AggregateRoot<RestaurantId> {
|
||||
private final List<Product> products;
|
||||
private final boolean isActive;
|
||||
|
||||
private Restaurant(Builder builder) {
|
||||
super.setId(builder.restaurantId);
|
||||
products = builder.products;
|
||||
isActive = builder.isActive;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public List<Product> getProducts() {
|
||||
return products;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
|
||||
public static final class Builder {
|
||||
private RestaurantId restaurantId;
|
||||
private List<Product> products;
|
||||
private boolean isActive;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder id(RestaurantId val) {
|
||||
restaurantId = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder products(List<Product> val) {
|
||||
products = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder isActive(boolean val) {
|
||||
isActive = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Restaurant build() {
|
||||
return new Restaurant(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.food.order.system.domain.event;
|
||||
|
||||
import com.food.order.system.domain.entity.Order;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class OrderCancelledEvent extends OrderEvent {
|
||||
|
||||
public OrderCancelledEvent(Order order, ZonedDateTime utc) {
|
||||
super(order, utc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.food.order.system.domain.event;
|
||||
|
||||
import com.food.order.system.domain.entity.Order;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class OrderCreatedEvent extends OrderEvent {
|
||||
public OrderCreatedEvent(Order order, ZonedDateTime createdAt) {
|
||||
super(order, createdAt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.food.order.system.domain.event;
|
||||
|
||||
import com.food.order.domain.event.DomainEvent;
|
||||
import com.food.order.system.domain.entity.Order;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public abstract class OrderEvent implements DomainEvent<Order> {
|
||||
private final Order order;
|
||||
private final ZonedDateTime createdAt;
|
||||
|
||||
protected OrderEvent(Order order, ZonedDateTime createdAt) {
|
||||
this.order = order;
|
||||
this.createdAt = ZonedDateTime.now();
|
||||
}
|
||||
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public ZonedDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.food.order.system.domain.event;
|
||||
|
||||
import com.food.order.system.domain.entity.Order;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
public class OrderPaidEvent extends OrderEvent {
|
||||
|
||||
public OrderPaidEvent(Order order, ZonedDateTime utc) {
|
||||
super(order, utc);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.food.order.system.domain.exception;
|
||||
|
||||
import com.food.order.domain.exception.DomainException;
|
||||
|
||||
public class OrderDomainException extends DomainException {
|
||||
|
||||
public OrderDomainException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public OrderDomainException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.food.order.system.domain.service;
|
||||
|
||||
import com.food.order.system.domain.entity.Order;
|
||||
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.OrderPaidEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface OrderDomainService {
|
||||
|
||||
OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant);
|
||||
|
||||
OrderPaidEvent payOrder(Order order);
|
||||
|
||||
void approve(Order order);
|
||||
|
||||
OrderCancelledEvent cancelOrderPayment(Order order, List<String> failureMessages);
|
||||
|
||||
void cancelOrder(Order order, List<String> failureMessages);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.food.order.system.domain.service.impl;
|
||||
|
||||
import com.food.order.system.domain.entity.Order;
|
||||
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.OrderPaidEvent;
|
||||
import com.food.order.system.domain.exception.OrderDomainException;
|
||||
import com.food.order.system.domain.service.OrderDomainService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class OrderDomainServiceImpl implements OrderDomainService {
|
||||
|
||||
private static final String UTC = "UTC";
|
||||
|
||||
@Override
|
||||
public OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant) {
|
||||
validateRestaurant(restaurant);
|
||||
setOrderProductInformation(order,restaurant);
|
||||
order.validateOrder();
|
||||
order.initializeOrder();
|
||||
log.info("Order with id {} initialize successfully", order.getId().getValue());
|
||||
return new OrderCreatedEvent(order, ZonedDateTime.now(ZoneId.of(UTC)));
|
||||
}
|
||||
|
||||
private void setOrderProductInformation(Order order, Restaurant restaurant) {
|
||||
order.getItems()
|
||||
.forEach(orderItem -> restaurant.getProducts().forEach(restaurantProduct -> {
|
||||
var currentProduct = orderItem.getProduct();
|
||||
if(currentProduct.equals(restaurantProduct)){
|
||||
currentProduct.updateWithConfirmedNameAndPrice(restaurantProduct.getName(),restaurantProduct.getPrice());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void validateRestaurant(Restaurant restaurant) {
|
||||
if (Boolean.FALSE.equals(restaurant.isActive())) {
|
||||
throw new OrderDomainException("Restaurant is not active, please try again later. " +
|
||||
"Restaurant id: {} " + restaurant.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderPaidEvent payOrder(Order order) {
|
||||
order.pay();
|
||||
log.info("Order with id {} paid successfully", order.getId().getValue());
|
||||
return new OrderPaidEvent(order, ZonedDateTime.now(ZoneId.of(UTC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void approve(Order order) {
|
||||
order.approve();
|
||||
log.info("Order with id {} approved successfully", order.getId().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderCancelledEvent cancelOrderPayment(Order order, List<String> failureMessages) {
|
||||
order.initCancel(failureMessages);
|
||||
log.info("Order with id {} cancelled successfully", order.getId().getValue());
|
||||
return new OrderCancelledEvent(order, ZonedDateTime.now(ZoneId.of(UTC)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelOrder(Order order, List<String> failureMessages) {
|
||||
order.cancel(failureMessages);
|
||||
log.info("Order with id {} cancelled successfully", order.getId().getValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.food.order.system.domain.valueobject;
|
||||
|
||||
import com.food.order.domain.valueobject.BaseId;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class OrderItemId extends BaseId<Long> {
|
||||
|
||||
public OrderItemId(Long id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.food.order.system.domain.valueobject;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class StreetAddress {
|
||||
|
||||
private final UUID id;
|
||||
private final String street;
|
||||
private final String city;
|
||||
private final String postalCode;
|
||||
|
||||
public StreetAddress(UUID id, String street, String city, String postalCode) {
|
||||
this.id = id;
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.postalCode = postalCode;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public String getPostalCode() {
|
||||
return postalCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof StreetAddress that)) return false;
|
||||
return id.equals(that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.food.order.system.domain.valueobject;
|
||||
|
||||
import com.food.order.domain.valueobject.BaseId;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class TrackingId extends BaseId<UUID> {
|
||||
public TrackingId(UUID id) {
|
||||
super(id);
|
||||
}
|
||||
}
|
||||
13
pom.xml
13
pom.xml
@@ -73,6 +73,19 @@
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
Reference in New Issue
Block a user