diff --git a/common/common-application/pom.xml b/common/common-application/pom.xml new file mode 100644 index 0000000..ef98914 --- /dev/null +++ b/common/common-application/pom.xml @@ -0,0 +1,26 @@ + + + + common + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + common-application + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + \ No newline at end of file diff --git a/common/common-application/src/main/java/com/food/order/system/application/handler/ErrorDTO.java b/common/common-application/src/main/java/com/food/order/system/application/handler/ErrorDTO.java new file mode 100644 index 0000000..701dfd4 --- /dev/null +++ b/common/common-application/src/main/java/com/food/order/system/application/handler/ErrorDTO.java @@ -0,0 +1,7 @@ +package com.food.order.system.application.handler; + +import lombok.Builder; + +@Builder +public record ErrorDTO(String code, String message) { +} diff --git a/common/common-application/src/main/java/com/food/order/system/application/handler/GlobalExceptionHandler.java b/common/common-application/src/main/java/com/food/order/system/application/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..a8ace14 --- /dev/null +++ b/common/common-application/src/main/java/com/food/order/system/application/handler/GlobalExceptionHandler.java @@ -0,0 +1,59 @@ +package com.food.order.system.application.handler; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.ValidationException; +import java.util.stream.Collectors; + +@Slf4j +@ControllerAdvice +public class GlobalExceptionHandler { + + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(value = {Exception.class}) + @ResponseBody + public ErrorDTO handleOrderDomainException(Exception e) { + log.error("Error occurred: {}", e.getMessage()); + return ErrorDTO.builder() + .code(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()) + .message("Unknown error occurred") + .build(); + } + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(value = {ValidationException.class}) + @ResponseBody + public ErrorDTO handleOrderDomainException(ValidationException e) { + ErrorDTO errorDTO; + if (e instanceof ConstraintViolationException) { + String violations = extractViolationsFromException((ConstraintViolationException) e); + log.error("Error occurred: {}", violations); + errorDTO = ErrorDTO.builder() + .code(HttpStatus.BAD_REQUEST.getReasonPhrase()) + .message(violations) + .build(); + } + else { + log.error("Error occurred: {}", e.getMessage()); + errorDTO = ErrorDTO.builder() + .code(HttpStatus.BAD_REQUEST.getReasonPhrase()) + .message(e.getMessage()) + .build(); + } + return errorDTO; + } + + private String extractViolationsFromException(ConstraintViolationException e) { + return e.getConstraintViolations() + .stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.joining("->")); + } +} diff --git a/common/pom.xml b/common/pom.xml index 3aaef7e..54296de 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -13,6 +13,7 @@ pom common-domain + common-application diff --git a/order-service/order-app/pom.xml b/order-service/order-app/pom.xml index 06d5b62..5290602 100644 --- a/order-service/order-app/pom.xml +++ b/order-service/order-app/pom.xml @@ -19,6 +19,21 @@ com.food.order order-application-service + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-validation + + + + com.food.order + common-application + \ No newline at end of file diff --git a/order-service/order-app/src/main/java/com/food/order/system/service/app/api/OrderController.java b/order-service/order-app/src/main/java/com/food/order/system/service/app/api/OrderController.java new file mode 100644 index 0000000..5429e96 --- /dev/null +++ b/order-service/order-app/src/main/java/com/food/order/system/service/app/api/OrderController.java @@ -0,0 +1,43 @@ +package com.food.order.system.service.app.api; + +import com.food.order.domain.dto.create.CreateOrderCommand; +import com.food.order.domain.dto.create.CreateOrderResponse; +import com.food.order.domain.dto.track.TrackOrderQuery; +import com.food.order.domain.dto.track.TrackOrderResponse; +import com.food.order.domain.ports.input.service.OrderApplicationService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.annotation.RequestScope; + +import java.util.UUID; + +@RestController +@CrossOrigin +@RequestScope +@RequiredArgsConstructor +@Slf4j +@Validated +@RequestMapping(value = "/api/orders", produces = "application/vnd.api.v1+json") +public class OrderController { + + private final OrderApplicationService orderApplicationService; + + @PostMapping + public ResponseEntity createOrder(@RequestBody CreateOrderCommand createOrderCommand) { + log.info("Creating order with command: {}", createOrderCommand); + CreateOrderResponse createOrderResponse = orderApplicationService.createOrder(createOrderCommand); + log.info("Created order with tracking id: {}", createOrderResponse.orderTrackingId()); + return ResponseEntity.ok(createOrderResponse); + } + + @GetMapping("/{orderTrackingId}") + public ResponseEntity trackOrder(@PathVariable("orderTrackingId") UUID orderTrackingId) { + TrackOrderResponse trackOrderResponse = orderApplicationService.trackOrder + (new TrackOrderQuery(orderTrackingId)); + log.info("Tracked order with tracking id: {}", orderTrackingId); + return ResponseEntity.ok(trackOrderResponse); + } +} diff --git a/order-service/order-app/src/main/java/com/food/order/system/service/app/exception/OrderGlobalException.java b/order-service/order-app/src/main/java/com/food/order/system/service/app/exception/OrderGlobalException.java new file mode 100644 index 0000000..113e6ca --- /dev/null +++ b/order-service/order-app/src/main/java/com/food/order/system/service/app/exception/OrderGlobalException.java @@ -0,0 +1,42 @@ +package com.food.order.system.service.app.exception; + +import com.food.order.system.application.handler.ErrorDTO; +import com.food.order.system.application.handler.GlobalExceptionHandler; +import com.food.order.system.domain.exception.OrderDomainException; +import com.food.order.system.domain.exception.OrderNotFoundException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ControllerAdvice +@Slf4j +public class OrderGlobalException extends GlobalExceptionHandler { + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(value = {OrderDomainException.class}) + @ResponseBody + public ErrorDTO handleOrderDomainException(OrderDomainException e) { + log.error("Error occurred: {}", e.getMessage()); + return ErrorDTO.builder() + .code(HttpStatus.BAD_REQUEST.getReasonPhrase()) + .message(e.getMessage()) + .build(); + } + + @ResponseStatus(HttpStatus.NOT_FOUND) + @ExceptionHandler(value = {OrderNotFoundException.class}) + @ResponseBody + public ErrorDTO handleOrderDomainException(OrderNotFoundException e) { + log.error("Error occurred: {}", e.getMessage()); + return ErrorDTO.builder() + .code(HttpStatus.NOT_FOUND.getReasonPhrase()) + .message(e.getMessage()) + .build(); + } + + + +} diff --git a/order-service/order-data-access/pom.xml b/order-service/order-data-access/pom.xml index eb0839a..f85e3e8 100644 --- a/order-service/order-data-access/pom.xml +++ b/order-service/order-data-access/pom.xml @@ -19,6 +19,16 @@ com.food.order order-application-service + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.postgresql + postgresql + \ No newline at end of file diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/adapter/CustomerRepositoryImpl.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/adapter/CustomerRepositoryImpl.java new file mode 100644 index 0000000..783b089 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/adapter/CustomerRepositoryImpl.java @@ -0,0 +1,27 @@ +package com.food.order.system.data.access.customer.adapter; + +import com.food.order.domain.ports.output.repository.CustomerRepository; +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.domain.entity.Customer; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Optional; +import java.util.UUID; + +@Service +@RequiredArgsConstructor +public class CustomerRepositoryImpl implements CustomerRepository { + + + private final CustomerJPARepository customerJpaRepository; + private final CustomerDataAccessMapper customerDataAccessMapper; + + + @Override + public Optional findCustomer(UUID customerId) { + return customerJpaRepository.findById(customerId) + .map(customerDataAccessMapper::customerEntityToCustomer); + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/entity/CustomerEntity.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/entity/CustomerEntity.java new file mode 100644 index 0000000..ceb1d15 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/entity/CustomerEntity.java @@ -0,0 +1,23 @@ +package com.food.order.system.data.access.customer.entity; + +import lombok.*; +import org.hibernate.annotations.DynamicUpdate; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.UUID; + +@Entity +@DynamicUpdate +@Table(name = "order_customer_m_view",schema = "customer") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CustomerEntity { + + @Id + private UUID id; +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/mapper/CustomerDataAccessMapper.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/mapper/CustomerDataAccessMapper.java new file mode 100644 index 0000000..24db9f2 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/mapper/CustomerDataAccessMapper.java @@ -0,0 +1,14 @@ +package com.food.order.system.data.access.customer.mapper; + +import com.food.order.domain.valueobject.CustomerId; +import com.food.order.system.data.access.customer.entity.CustomerEntity; +import com.food.order.system.domain.entity.Customer; +import org.springframework.stereotype.Component; + +@Component +public class CustomerDataAccessMapper { + + public Customer customerEntityToCustomer(CustomerEntity customerEntity) { + return new Customer(new CustomerId(customerEntity.getId())); + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/repository/CustomerJPARepository.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/repository/CustomerJPARepository.java new file mode 100644 index 0000000..e550d0a --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/customer/repository/CustomerJPARepository.java @@ -0,0 +1,11 @@ +package com.food.order.system.data.access.customer.repository; + +import com.food.order.system.data.access.customer.entity.CustomerEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.UUID; + +@Repository +public interface CustomerJPARepository extends JpaRepository { +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/adapter/OrderRepositoryImpl.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/adapter/OrderRepositoryImpl.java new file mode 100644 index 0000000..335ca93 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/adapter/OrderRepositoryImpl.java @@ -0,0 +1,34 @@ +package com.food.order.system.data.access.order.adapter; + +import com.food.order.domain.ports.output.repository.OrderRepository; +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.domain.entity.Order; +import com.food.order.system.domain.valueobject.TrackingId; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +@Slf4j +public class OrderRepositoryImpl implements OrderRepository { + + private final OrderJpaRepository orderJpaRepository; + private final OrderDataAccessMapper orderDataAccessMapper; + + + @Override + public Order save(Order order) { + return orderDataAccessMapper.orderEntityToOrder(orderJpaRepository + .save(orderDataAccessMapper.orderToOrderEntity(order))); + } + + @Override + public Optional findByTrackingId(TrackingId trackingId) { + return orderJpaRepository.findByTrackingId(trackingId.getValue()) + .map(orderDataAccessMapper::orderEntityToOrder); + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderAddressEntity.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderAddressEntity.java new file mode 100644 index 0000000..e591b33 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderAddressEntity.java @@ -0,0 +1,41 @@ +package com.food.order.system.data.access.order.entity; + +import lombok.*; +import org.hibernate.annotations.DynamicUpdate; + +import javax.persistence.*; +import java.util.UUID; + +@Entity +@DynamicUpdate +@Table(name = "order_address") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrderAddressEntity { + + @Id + private UUID id; + + @OneToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "ORDER_ID") + private OrderEntity order; + + private String street; + private String city; + private String postalCode; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OrderAddressEntity that)) return false; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} \ No newline at end of file diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderEntity.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderEntity.java new file mode 100644 index 0000000..a5fc66d --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderEntity.java @@ -0,0 +1,55 @@ +package com.food.order.system.data.access.order.entity; + +import com.food.order.domain.valueobject.OrderStatus; +import lombok.*; +import org.hibernate.annotations.DynamicUpdate; + +import javax.persistence.*; +import java.math.BigDecimal; +import java.util.List; +import java.util.UUID; + +@Entity +@DynamicUpdate +@Table(name = "orders") +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrderEntity { + + @Id + private UUID id; + + private UUID customerId; + + private UUID restaurantId; + + private UUID trackingId; + + @Enumerated(EnumType.STRING) + private OrderStatus orderStatus; + + private BigDecimal price; + + private String failureMessages; + + @OneToOne(mappedBy = "order", cascade = CascadeType.ALL) + private OrderAddressEntity address; + + @OneToMany(mappedBy = "orderEntity", cascade = CascadeType.ALL) + private List items; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OrderEntity that)) return false; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderItemEntity.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderItemEntity.java new file mode 100644 index 0000000..750649a --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderItemEntity.java @@ -0,0 +1,50 @@ +package com.food.order.system.data.access.order.entity; + +import lombok.*; +import org.hibernate.annotations.DynamicUpdate; + +import javax.persistence.*; +import java.math.BigDecimal; +import java.util.UUID; + +@Entity +@DynamicUpdate +@Table(name = "order_items") +@IdClass(OrderItemEntityId.class) +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrderItemEntity { + + @Id + private Long id; + @Id + @ManyToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "ORDER_ID") + private OrderEntity orderEntity; + + private UUID productId; + + private Integer quantity; + + private BigDecimal price; + + private BigDecimal subTotal; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OrderItemEntity that)) return false; + if (!id.equals(that.id)) return false; + return orderEntity.equals(that.orderEntity); + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + orderEntity.hashCode(); + return result; + } +} \ No newline at end of file diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderItemEntityId.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderItemEntityId.java new file mode 100644 index 0000000..1521f1d --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/entity/OrderItemEntityId.java @@ -0,0 +1,29 @@ +package com.food.order.system.data.access.order.entity; + +import lombok.*; + +import java.io.Serializable; + + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OrderItemEntityId implements Serializable { + + private Long id; + private OrderEntity order; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OrderItemEntityId that)) return false; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/mapper/OrderDataAccessMapper.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/mapper/OrderDataAccessMapper.java new file mode 100644 index 0000000..d7c82b5 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/mapper/OrderDataAccessMapper.java @@ -0,0 +1,92 @@ +package com.food.order.system.data.access.order.mapper; + +import com.food.order.domain.valueobject.*; +import com.food.order.system.data.access.order.entity.OrderAddressEntity; +import com.food.order.system.data.access.order.entity.OrderEntity; +import com.food.order.system.data.access.order.entity.OrderItemEntity; +import com.food.order.system.domain.entity.Order; +import com.food.order.system.domain.entity.OrderItem; +import com.food.order.system.domain.entity.Product; +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 org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +import static com.food.order.system.domain.entity.Order.FAILURE_MESSAGE_DELIMITER; + +@Component +public class OrderDataAccessMapper { + + public OrderEntity orderToOrderEntity(Order order){ + OrderEntity orderEntity = new OrderEntity(); + orderEntity.setId(order.getId().getValue()); + orderEntity.setOrderStatus(order.getStatus()); + orderEntity.setCustomerId(order.getCustomerId().getValue()); + orderEntity.setRestaurantId(order.getRestaurantId().getValue()); + orderEntity.setTrackingId(order.getTrackingId().getValue()); + orderEntity.setAddress(deliveryAddressToAddressEntity(order.getDeliveryAddress())); + orderEntity.setPrice(order.getPrice().getAmount()); + orderEntity.setItems(orderItemsToOrderItemsEntity(order.getItems())); + orderEntity.setFailureMessages(order.getFailureMessages() != null ? + String.join(FAILURE_MESSAGE_DELIMITER, order.getFailureMessages()) : ""); + orderEntity.getAddress().setOrder(orderEntity); + orderEntity.getItems().forEach(item -> item.setOrderEntity(orderEntity)); + return orderEntity; + } + + public Order orderEntityToOrder(OrderEntity orderEntity){ + return Order.builder() + .orderId(new OrderId(orderEntity.getId())) + .customerId(new CustomerId(orderEntity.getCustomerId())) + .restaurantId(new RestaurantId(orderEntity.getRestaurantId())) + .deliveryAddress(addressEntityToDeliveryAddress(orderEntity.getAddress())) + .price(new Money(orderEntity.getPrice())) + .items(orderItemsEntityToOrderItems(orderEntity.getItems())) + .trackingId(new TrackingId(orderEntity.getTrackingId())) + .status(orderEntity.getOrderStatus()) + .failureMessages(orderEntity.getFailureMessages() != null ? + List.of(orderEntity.getFailureMessages().split(FAILURE_MESSAGE_DELIMITER)) : + new ArrayList<>()) + .build(); + } + + private List orderItemsEntityToOrderItems(List items) { + return items.stream() + .map(item -> OrderItem.builder() + .orderItemId(new OrderItemId(item.getId())) + .product(new Product(new ProductId(item.getProductId()))) + .quantity(item.getQuantity()) + .price(new Money(item.getPrice())) + .subTotal(new Money(item.getSubTotal())) + .build()) + .toList(); + } + + private StreetAddress addressEntityToDeliveryAddress(OrderAddressEntity address) { + return new StreetAddress(address.getId(),address.getStreet(), address.getCity() , address.getPostalCode()); + } + + private List orderItemsToOrderItemsEntity(List items) { + return items.stream() + .map(item -> OrderItemEntity.builder() + .id(item.getId().getValue()) + .productId(item.getProduct().getId().getValue()) + .price(item.getPrice().getAmount()) + .quantity(item.getQuantity()) + .subTotal(item.getSubTotal().getAmount()) + .build()) + .toList(); + } + + private OrderAddressEntity deliveryAddressToAddressEntity(StreetAddress deliveryAddress) { + OrderAddressEntity orderAddressEntity = new OrderAddressEntity(); + orderAddressEntity.setId(deliveryAddress.getId()); + orderAddressEntity.setStreet(deliveryAddress.getStreet()); + orderAddressEntity.setCity(deliveryAddress.getCity()); + orderAddressEntity.setPostalCode(deliveryAddress.getPostalCode()); + return orderAddressEntity; + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/repository/OrderJpaRepository.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/repository/OrderJpaRepository.java new file mode 100644 index 0000000..cc40b86 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/order/repository/OrderJpaRepository.java @@ -0,0 +1,16 @@ +package com.food.order.system.data.access.order.repository; + +import com.food.order.system.data.access.order.entity.OrderEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface OrderJpaRepository extends JpaRepository { + + Optional findByTrackingId(UUID trackingId); + + +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/adapter/RestaurantRepositoryImpl.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/adapter/RestaurantRepositoryImpl.java new file mode 100644 index 0000000..8f5d5ff --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/adapter/RestaurantRepositoryImpl.java @@ -0,0 +1,26 @@ +package com.food.order.system.data.access.restaurant.adapter; + +import com.food.order.domain.ports.output.repository.RestaurantRepository; +import com.food.order.system.data.access.restaurant.mapper.RestaurantDataAccessMapper; +import com.food.order.system.data.access.restaurant.repository.RestaurantJpaRepository; +import com.food.order.system.domain.entity.Restaurant; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class RestaurantRepositoryImpl implements RestaurantRepository { + + private final RestaurantJpaRepository restaurantJpaRepository; + private final RestaurantDataAccessMapper restaurantDataAccessMapper; + + @Override + public Optional findRestaurantInformation(Restaurant restaurant) { + return restaurantJpaRepository.findByRestaurantIdAndProductIdIn + (restaurant.getId().getValue(), + restaurantDataAccessMapper.restaurantToRestaurantProducts(restaurant)) + .map(restaurantDataAccessMapper::restaurantEntityToRestaurant); + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/entity/RestaurantEntity.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/entity/RestaurantEntity.java new file mode 100644 index 0000000..b3d73d8 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/entity/RestaurantEntity.java @@ -0,0 +1,51 @@ +package com.food.order.system.data.access.restaurant.entity; + + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.UUID; + +@Entity +@Table(name = "order_restaurant_m_view",schema = "restaurant") +@Getter +@Setter +@Builder +@IdClass(RestaurantEntityId.class) +@NoArgsConstructor +@AllArgsConstructor +public class RestaurantEntity { + + @Id + private UUID restaurantId; + + @Id + private UUID productId; + + private String restaurantName; + + private Boolean restaurantActive; + + private String productName; + + private BigDecimal productPrice; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RestaurantEntity that)) return false; + if (!restaurantId.equals(that.restaurantId)) return false; + return productId.equals(that.productId); + } + + @Override + public int hashCode() { + int result = restaurantId.hashCode(); + result = 31 * result + productId.hashCode(); + return result; + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/entity/RestaurantEntityId.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/entity/RestaurantEntityId.java new file mode 100644 index 0000000..46cbac3 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/entity/RestaurantEntityId.java @@ -0,0 +1,32 @@ +package com.food.order.system.data.access.restaurant.entity; + +import lombok.*; + +import java.io.Serializable; +import java.util.UUID; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RestaurantEntityId implements Serializable { + + private UUID restaurantId; + private UUID productId; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RestaurantEntityId that)) return false; + if (!restaurantId.equals(that.restaurantId)) return false; + return productId.equals(that.productId); + } + + @Override + public int hashCode() { + int result = restaurantId.hashCode(); + result = 31 * result + productId.hashCode(); + return result; + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/exception/RestaurantDataAccessException.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/exception/RestaurantDataAccessException.java new file mode 100644 index 0000000..6220767 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/exception/RestaurantDataAccessException.java @@ -0,0 +1,7 @@ +package com.food.order.system.data.access.restaurant.exception; + +public class RestaurantDataAccessException extends RuntimeException{ + public RestaurantDataAccessException(String s) { + super(s); + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/mapper/RestaurantDataAccessMapper.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/mapper/RestaurantDataAccessMapper.java new file mode 100644 index 0000000..690c4b9 --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/mapper/RestaurantDataAccessMapper.java @@ -0,0 +1,40 @@ +package com.food.order.system.data.access.restaurant.mapper; + +import com.food.order.domain.valueobject.Money; +import com.food.order.domain.valueobject.ProductId; +import com.food.order.domain.valueobject.RestaurantId; +import com.food.order.system.data.access.restaurant.entity.RestaurantEntity; +import com.food.order.system.data.access.restaurant.exception.RestaurantDataAccessException; +import com.food.order.system.domain.entity.Product; +import com.food.order.system.domain.entity.Restaurant; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.UUID; + +@Component +public class RestaurantDataAccessMapper { + + public List restaurantToRestaurantProducts(Restaurant restaurant) { + return restaurant.getProducts() + .stream() + .map(product -> product.getId().getValue()) + .toList(); + } + + public Restaurant restaurantEntityToRestaurant(List restaurantEntities) { + var restaurantEntity = + restaurantEntities.stream().findFirst() + .orElseThrow(() -> new RestaurantDataAccessException("No restaurant found")); + var restaurantProducts = restaurantEntities.stream() + .map(entity -> new Product(new ProductId(entity.getProductId()), + entity.getProductName(), + new Money(entity.getProductPrice()))).toList(); + return Restaurant.builder() + .id(new RestaurantId(restaurantEntity.getRestaurantId())) + .products(restaurantProducts) + .isActive(restaurantEntity.getRestaurantActive()) + .build(); + + } +} diff --git a/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/repository/RestaurantJpaRepository.java b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/repository/RestaurantJpaRepository.java new file mode 100644 index 0000000..def551d --- /dev/null +++ b/order-service/order-data-access/src/main/java/com/food/order/system/data/access/restaurant/repository/RestaurantJpaRepository.java @@ -0,0 +1,14 @@ +package com.food.order.system.data.access.restaurant.repository; + +import com.food.order.system.data.access.restaurant.entity.RestaurantEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface RestaurantJpaRepository extends JpaRepository { + Optional> findByRestaurantIdAndProductIdIn(UUID restaurantId, List productIds); +} diff --git a/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/create/CreateOrderCommand.java b/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/create/CreateOrderCommand.java index 3fa1d62..7ba2a43 100644 --- a/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/create/CreateOrderCommand.java +++ b/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/create/CreateOrderCommand.java @@ -1,8 +1,6 @@ package com.food.order.domain.dto.create; -import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.Getter; import javax.validation.constraints.NotNull; import java.math.BigDecimal; diff --git a/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/track/TrackOrderQuery.java b/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/track/TrackOrderQuery.java index 7a96a60..d0db11a 100644 --- a/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/track/TrackOrderQuery.java +++ b/order-service/order-domain/order-application-service/src/main/java/com/food/order/domain/dto/track/TrackOrderQuery.java @@ -1,6 +1,5 @@ package com.food.order.domain.dto.track; -import lombok.AllArgsConstructor; import lombok.Builder; import javax.validation.constraints.NotNull; diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Customer.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Customer.java index 626e8cd..978f5c6 100644 --- a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Customer.java +++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Customer.java @@ -4,4 +4,11 @@ import com.food.order.domain.entity.AggregateRoot; import com.food.order.domain.valueobject.CustomerId; public class Customer extends AggregateRoot { + + public Customer(){ + + } + public Customer (CustomerId id) { + super.setId(id); + } } diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Order.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Order.java index 509eced..f74a770 100644 --- a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Order.java +++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/entity/Order.java @@ -13,6 +13,8 @@ import java.util.UUID; public class Order extends AggregateRoot { + public static final String FAILURE_MESSAGE_DELIMITER = ","; + private final CustomerId customerId; private final RestaurantId restaurantId; private final StreetAddress deliveryAddress; diff --git a/pom.xml b/pom.xml index fb3ce3a..88843bb 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,11 @@ ${project.version} + + com.food.order + common-application + ${project.version} + com.food.order