This commit is contained in:
Ali CANLI
2022-07-12 12:48:42 +03:00
parent f4e7ee19cf
commit 2377262b64
81 changed files with 756 additions and 221 deletions

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.entity; package com.food.order.sysyem.entity;
public abstract class AggregateRoot<ID> extends BaseEntity<ID> { public abstract class AggregateRoot<ID> extends BaseEntity<ID> {

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.entity; package com.food.order.sysyem.entity;
public abstract class BaseEntity<ID> { public abstract class BaseEntity<ID> {
private ID id; private ID id;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.event; package com.food.order.sysyem.event;
// Base Domain Event Generic Class // Base Domain Event Generic Class

View File

@@ -1,6 +1,6 @@
package com.food.order.domain.event.publisher; package com.food.order.sysyem.event.publisher;
import com.food.order.domain.event.DomainEvent; import com.food.order.sysyem.event.DomainEvent;
public interface DomainEventPublisher <T extends DomainEvent> { public interface DomainEventPublisher <T extends DomainEvent> {
void publish(T event); void publish(T event);

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.exception; package com.food.order.sysyem.exception;
public class DomainException extends RuntimeException { public class DomainException extends RuntimeException {

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
public abstract class BaseId<T> { public abstract class BaseId<T> {

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
import java.util.UUID; import java.util.UUID;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
public enum OrderApprovalStatus { public enum OrderApprovalStatus {
APPROVED, APPROVED,

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
import java.util.UUID; import java.util.UUID;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
public enum OrderStatus { public enum OrderStatus {
PENDING, PENDING,

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
public enum PaymentStatus { public enum PaymentStatus {
COMPLETED,CANCELED,FAILED COMPLETED,CANCELED,FAILED

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
import java.util.UUID; import java.util.UUID;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.valueobject; package com.food.order.sysyem.valueobject;
import java.util.UUID; import java.util.UUID;

View File

@@ -5,5 +5,5 @@ import org.apache.avro.specific.SpecificRecordBase;
import java.util.List; import java.util.List;
public interface KafkaConsumer<T extends SpecificRecordBase> { public interface KafkaConsumer<T extends SpecificRecordBase> {
void receive(List<T> messages , List<Long> keys , List<Integer> partitions , List<Long> offSets); void receive(List<T> messages , List<String> keys , List<Integer> partitions , List<Long> offSets);
} }

View File

@@ -1,10 +1,10 @@
package com.food.order.system.service.app.api; package com.food.order.system.service.app.api;
import com.food.order.domain.dto.create.CreateOrderCommand; import com.food.order.sysyem.dto.create.CreateOrderCommand;
import com.food.order.domain.dto.create.CreateOrderResponse; import com.food.order.sysyem.dto.create.CreateOrderResponse;
import com.food.order.domain.dto.track.TrackOrderQuery; import com.food.order.sysyem.dto.track.TrackOrderQuery;
import com.food.order.domain.dto.track.TrackOrderResponse; import com.food.order.sysyem.dto.track.TrackOrderResponse;
import com.food.order.domain.ports.input.service.OrderApplicationService; import com.food.order.sysyem.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;

View File

@@ -35,7 +35,36 @@
<groupId>com.food.order</groupId> <groupId>com.food.order</groupId>
<artifactId>order-messaging</artifactId> <artifactId>order-messaging</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>${project.groupId}/order.service:${project.version}</name>
</image>
</configuration>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> </project>

View File

@@ -0,0 +1,15 @@
package com.food.order.system.order.domain;
import com.food.order.system.domain.service.OrderDomainService;
import com.food.order.system.domain.service.impl.OrderDomainServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public OrderDomainService orderDomainService() {
return new OrderDomainServiceImpl();
}
}

View File

@@ -0,0 +1,15 @@
package com.food.order.system.order.domain;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories("com.food.order.system.data.access")
@EntityScan(basePackages = "com.food.order.system.data.access")
@SpringBootApplication(scanBasePackages = "com.food.order.system")
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}

View File

@@ -0,0 +1,67 @@
server:
port: 3232
logging:
level:
com.food.order.system : DEBUG
order-service:
payment-request-topic-name: payment-request
payment-response-topic-name: payment-response
restaurant-approval-request-topic-name: restaurant-approval-request
restaurant-approval-response-topic-name: restaurant-approval-response
spring:
jpa:
open-in-view: false
show-sql: true
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQL9Dialect
datasource:
url: jdbc:postgresql://localhost:5432/postgres?currentSchema=order&binaryTransfer=true&reWriteBatchedInserts=true&stringtype=unspecified
username: postgres
password: postgres
driverClassName: org.postgresql.Driver
sql:
init:
platform: postgres
mode: always
schema-locations: classpath:init-schema.sql
kafka-config:
bootstrap-servers: localhost:19092, localhost:29092, localhost:39092
schema-registry-url-key: schema.registry.url
schema-registry-url: http://localhost:8081
num-of-partitions: 3
replication-factor: 3
kafka-producer-config:
key-serializer-class: org.apache.kafka.common.serialization.StringSerializer
value-serializer-class: io.confluent.kafka.serializers.KafkaAvroSerializer
compression-type: snappy
acks: all
batch-size: 16384
batch-size-boost-factor: 100
linger-ms: 5
request-timeout-ms: 60000
retry-count: 5
kafka-consumer-config:
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: io.confluent.kafka.serializers.KafkaAvroDeserializer
payment-consumer-group-id: payment-topic-consumer
restaurant-approval-consumer-group-id: restaurant-approval-topic-consumer
auto-offset-reset: earliest
specific-avro-reader-key: specific.avro.reader
specific-avro-reader: true
batch-listener: true
auto-startup: true
concurrency-level: 3
session-timeout-ms: 10000
heartbeat-interval-ms: 3000
max-poll-interval-ms: 300000
max-poll-records: 500
max-partition-fetch-bytes-default: 1048576
max-partition-fetch-bytes-boost-factor: 1
poll-timeout-ms: 150

View File

@@ -0,0 +1,61 @@
DROP SCHEMA IF EXISTS "order" CASCADE;
CREATE SCHEMA "order";
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
DROP TYPE IF EXISTS order_status;
CREATE TYPE order_status AS ENUM ('PENDING', 'PAID', 'APPROVED', 'CANCELLED', 'CANCELLING');
DROP TABLE IF EXISTS "order".orders CASCADE;
CREATE TABLE "order".orders
(
id uuid NOT NULL,
customer_id uuid NOT NULL,
restaurant_id uuid NOT NULL,
tracking_id uuid NOT NULL,
price numeric(10,2) NOT NULL,
order_status order_status NOT NULL,
failure_messages character varying COLLATE pg_catalog."default",
CONSTRAINT orders_pkey PRIMARY KEY (id)
);
DROP TABLE IF EXISTS "order".order_items CASCADE;
CREATE TABLE "order".order_items
(
id bigint NOT NULL,
order_id uuid NOT NULL,
product_id uuid NOT NULL,
price numeric(10,2) NOT NULL,
quantity integer NOT NULL,
sub_total numeric(10,2) NOT NULL,
CONSTRAINT order_items_pkey PRIMARY KEY (id, order_id)
);
ALTER TABLE "order".order_items
ADD CONSTRAINT "FK_ORDER_ID" FOREIGN KEY (order_id)
REFERENCES "order".orders (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
NOT VALID;
DROP TABLE IF EXISTS "order".order_address CASCADE;
CREATE TABLE "order".order_address
(
id uuid NOT NULL,
order_id uuid UNIQUE NOT NULL,
street character varying COLLATE pg_catalog."default" NOT NULL,
postal_code character varying COLLATE pg_catalog."default" NOT NULL,
city character varying COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT order_address_pkey PRIMARY KEY (id, order_id)
);
ALTER TABLE "order".order_address
ADD CONSTRAINT "FK_ORDER_ID" FOREIGN KEY (order_id)
REFERENCES "order".orders (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
NOT VALID;

View File

@@ -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.domain.ports.output.repository.CustomerRepository; import com.food.order.sysyem.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;

View File

@@ -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.domain.valueobject.CustomerId; import com.food.order.sysyem.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;

View File

@@ -1,6 +1,6 @@
package com.food.order.system.data.access.order.adapter; package com.food.order.system.data.access.order.adapter;
import com.food.order.domain.ports.output.repository.OrderRepository; 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;

View File

@@ -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.domain.valueobject.OrderStatus; import com.food.order.sysyem.valueobject.OrderStatus;
import lombok.*; import lombok.*;
import org.hibernate.annotations.DynamicUpdate; import org.hibernate.annotations.DynamicUpdate;

View File

@@ -6,7 +6,6 @@ import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*; import javax.persistence.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
@Entity @Entity
@DynamicUpdate @DynamicUpdate
@Table(name = "order_items") @Table(name = "order_items")

View File

@@ -3,6 +3,7 @@ package com.food.order.system.data.access.order.entity;
import lombok.*; import lombok.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
@Getter @Getter
@@ -13,17 +14,18 @@ import java.io.Serializable;
public class OrderItemEntityId implements Serializable { public class OrderItemEntityId implements Serializable {
private Long id; private Long id;
private OrderEntity order; private OrderEntity orderEntity;
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (!(o instanceof OrderItemEntityId that)) return false; if (o == null || getClass() != o.getClass()) return false;
return id.equals(that.id); OrderItemEntityId that = (OrderItemEntityId) o;
return id.equals(that.id) && orderEntity.equals(that.orderEntity);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return id.hashCode(); return Objects.hash(id, orderEntity);
} }
} }

View File

@@ -1,6 +1,5 @@
package com.food.order.system.data.access.order.mapper; 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.OrderAddressEntity;
import com.food.order.system.data.access.order.entity.OrderEntity; 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.data.access.order.entity.OrderItemEntity;
@@ -10,6 +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 org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;

View File

@@ -1,6 +1,6 @@
package com.food.order.system.data.access.restaurant.adapter; package com.food.order.system.data.access.restaurant.adapter;
import com.food.order.domain.ports.output.repository.RestaurantRepository; import com.food.order.sysyem.ports.output.repository.RestaurantRepository;
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.data.access.restaurant.repository.RestaurantJpaRepository; import com.food.order.system.data.access.restaurant.repository.RestaurantJpaRepository;
import com.food.order.system.domain.entity.Restaurant; import com.food.order.system.domain.entity.Restaurant;

View File

@@ -1,8 +1,8 @@
package com.food.order.system.data.access.restaurant.mapper; package com.food.order.system.data.access.restaurant.mapper;
import com.food.order.domain.valueobject.Money; import com.food.order.sysyem.valueobject.Money;
import com.food.order.domain.valueobject.ProductId; import com.food.order.sysyem.valueobject.ProductId;
import com.food.order.domain.valueobject.RestaurantId; import com.food.order.sysyem.valueobject.RestaurantId;
import com.food.order.system.data.access.restaurant.entity.RestaurantEntity; 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.data.access.restaurant.exception.RestaurantDataAccessException;
import com.food.order.system.domain.entity.Product; import com.food.order.system.domain.entity.Product;

View File

@@ -1,15 +0,0 @@
package com.food.order.domain.ports.input.service;
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 javax.validation.Valid;
public interface OrderApplicationService {
CreateOrderResponse createOrder(@Valid CreateOrderCommand createOrderCommand);
TrackOrderResponse trackOrder(@Valid TrackOrderQuery trackOrderQuery);
}

View File

@@ -1,8 +0,0 @@
package com.food.order.domain.ports.output.message.publisher.restaurantapproval;
import com.food.order.domain.event.publisher.DomainEventPublisher;
import com.food.order.system.domain.event.OrderPaidEvent;
public interface OrderPaidRestaurantRequestMessagePublisher extends DomainEventPublisher<OrderPaidEvent> {
}

View File

@@ -1,16 +1,16 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.dto.create.CreateOrderCommand; import com.food.order.sysyem.dto.create.CreateOrderCommand;
import com.food.order.domain.dto.create.CreateOrderResponse; import com.food.order.sysyem.dto.create.CreateOrderResponse;
import com.food.order.domain.dto.track.TrackOrderQuery; import com.food.order.sysyem.dto.track.TrackOrderQuery;
import com.food.order.domain.dto.track.TrackOrderResponse; import com.food.order.sysyem.dto.track.TrackOrderResponse;
import com.food.order.domain.ports.input.service.OrderApplicationService; import com.food.order.sysyem.ports.input.service.OrderApplicationService;
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.Component;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@Service @Component
@Validated @Validated
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor

View File

@@ -1,9 +1,9 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.dto.create.CreateOrderCommand; import com.food.order.sysyem.dto.create.CreateOrderCommand;
import com.food.order.domain.dto.create.CreateOrderResponse; import com.food.order.sysyem.dto.create.CreateOrderResponse;
import com.food.order.domain.mapper.OrderDataMapper; import com.food.order.sysyem.mapper.OrderDataMapper;
import com.food.order.domain.ports.output.message.publisher.payment.OrderCreatedPaymentRequestMessagePublisher; import com.food.order.sysyem.ports.output.message.publisher.payment.OrderCreatedPaymentRequestMessagePublisher;
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;

View File

@@ -1,10 +1,10 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.dto.create.CreateOrderCommand; import com.food.order.sysyem.dto.create.CreateOrderCommand;
import com.food.order.domain.mapper.OrderDataMapper; import com.food.order.sysyem.mapper.OrderDataMapper;
import com.food.order.domain.ports.output.repository.CustomerRepository; import com.food.order.sysyem.ports.output.repository.CustomerRepository;
import com.food.order.domain.ports.output.repository.OrderRepository; import com.food.order.sysyem.ports.output.repository.OrderRepository;
import com.food.order.domain.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;

View File

@@ -1,9 +1,9 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.dto.track.TrackOrderQuery; import com.food.order.sysyem.dto.track.TrackOrderQuery;
import com.food.order.domain.dto.track.TrackOrderResponse; import com.food.order.sysyem.dto.track.TrackOrderResponse;
import com.food.order.domain.mapper.OrderDataMapper; import com.food.order.sysyem.mapper.OrderDataMapper;
import com.food.order.domain.ports.output.repository.OrderRepository; import com.food.order.sysyem.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;

View File

@@ -1,7 +1,7 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.dto.message.PaymentResponse; import com.food.order.sysyem.dto.message.PaymentResponse;
import com.food.order.domain.ports.input.message.listener.payment.PaymentResponseMessageListener; import com.food.order.sysyem.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.stereotype.Service; import org.springframework.stereotype.Service;

View File

@@ -1,7 +1,7 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.dto.message.RestaurantApprovalResponse; import com.food.order.sysyem.dto.message.RestaurantApprovalResponse;
import com.food.order.domain.ports.input.message.listener.restaurantapproval.RestaurantApprovalResponseMessageListener; import com.food.order.sysyem.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.stereotype.Service; import org.springframework.stereotype.Service;

View File

@@ -0,0 +1,15 @@
package com.food.order.sysyem.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "order-service")
public class OrderServiceConfigData {
private String paymentRequestTopicName;
private String paymentResponseTopicName;
private String restaurantApprovalRequestTopicName;
private String restaurantApprovalResponseTopicName;
}

View File

@@ -1,7 +1,6 @@
package com.food.order.domain.dto.create; package com.food.order.sysyem.dto.create;
import com.food.order.domain.valueobject.OrderStatus; import com.food.order.sysyem.valueobject.OrderStatus;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.dto.create; package com.food.order.sysyem.dto.create;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.dto.create; package com.food.order.sysyem.dto.create;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;

View File

@@ -1,11 +1,12 @@
package com.food.order.domain.dto.message; package com.food.order.sysyem.dto.message;
import com.food.order.domain.valueobject.PaymentStatus; import com.food.order.sysyem.valueobject.PaymentStatus;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.Instant;
import java.util.List; import java.util.List;
@Getter @Getter
@@ -19,6 +20,7 @@ public class PaymentResponse {
private String paymentId; private String paymentId;
private String customerId; private String customerId;
private BigDecimal price; private BigDecimal price;
private Instant createdAt;
private PaymentStatus paymentStatus; private PaymentStatus paymentStatus;
private List<String> failureMessages; private List<String> failureMessages;
} }

View File

@@ -1,6 +1,6 @@
package com.food.order.domain.dto.message; package com.food.order.sysyem.dto.message;
import com.food.order.domain.valueobject.OrderApprovalStatus; import com.food.order.sysyem.valueobject.OrderApprovalStatus;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;

View File

@@ -1,7 +1,6 @@
package com.food.order.domain.dto.track; package com.food.order.sysyem.dto.track;
import com.food.order.domain.valueobject.OrderStatus; import com.food.order.sysyem.valueobject.OrderStatus;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;

View File

@@ -1,13 +1,13 @@
package com.food.order.domain.mapper; package com.food.order.sysyem.mapper;
import com.food.order.domain.dto.create.CreateOrderCommand; import com.food.order.sysyem.dto.create.CreateOrderCommand;
import com.food.order.domain.dto.create.CreateOrderResponse; import com.food.order.sysyem.dto.create.CreateOrderResponse;
import com.food.order.domain.dto.create.OrderAddress; import com.food.order.sysyem.dto.create.OrderAddress;
import com.food.order.domain.dto.track.TrackOrderResponse; import com.food.order.sysyem.dto.track.TrackOrderResponse;
import com.food.order.domain.valueobject.CustomerId; import com.food.order.sysyem.valueobject.CustomerId;
import com.food.order.domain.valueobject.Money; import com.food.order.sysyem.valueobject.Money;
import com.food.order.domain.valueobject.ProductId; import com.food.order.sysyem.valueobject.ProductId;
import com.food.order.domain.valueobject.RestaurantId; import com.food.order.sysyem.valueobject.RestaurantId;
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;
@@ -53,7 +53,7 @@ public class OrderDataMapper {
.build(); .build();
} }
private List<OrderItem> orderItemsToOrderItemEntities(List<com.food.order.domain.dto.create.OrderItem> orderItems) { private List<OrderItem> orderItemsToOrderItemEntities(List<com.food.order.sysyem.dto.create.OrderItem> orderItems) {
return orderItems.stream() return orderItems.stream()
.map(orderItem -> .map(orderItem ->
OrderItem.builder() OrderItem.builder()

View File

@@ -1,6 +1,6 @@
package com.food.order.domain.ports.input.message.listener.payment; package com.food.order.sysyem.ports.input.message.listener.payment;
import com.food.order.domain.dto.message.PaymentResponse; import com.food.order.sysyem.dto.message.PaymentResponse;
public interface PaymentResponseMessageListener { public interface PaymentResponseMessageListener {

View File

@@ -1,6 +1,6 @@
package com.food.order.domain.ports.input.message.listener.restaurantapproval; package com.food.order.sysyem.ports.input.message.listener.restaurantapproval;
import com.food.order.domain.dto.message.RestaurantApprovalResponse; import com.food.order.sysyem.dto.message.RestaurantApprovalResponse;
public interface RestaurantApprovalResponseMessageListener { public interface RestaurantApprovalResponseMessageListener {
void orderApproved(RestaurantApprovalResponse restaurantApprovalResponse); void orderApproved(RestaurantApprovalResponse restaurantApprovalResponse);

View File

@@ -0,0 +1,15 @@
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);
}

View File

@@ -1,6 +1,6 @@
package com.food.order.domain.ports.output.message.publisher.payment; package com.food.order.sysyem.ports.output.message.publisher.payment;
import com.food.order.domain.event.publisher.DomainEventPublisher; import com.food.order.sysyem.event.publisher.DomainEventPublisher;
import com.food.order.system.domain.event.OrderCancelledEvent; import com.food.order.system.domain.event.OrderCancelledEvent;
public interface OrderCancelledPaymentRequestMessagePublisher extends DomainEventPublisher<OrderCancelledEvent> { public interface OrderCancelledPaymentRequestMessagePublisher extends DomainEventPublisher<OrderCancelledEvent> {

View File

@@ -1,6 +1,6 @@
package com.food.order.domain.ports.output.message.publisher.payment; package com.food.order.sysyem.ports.output.message.publisher.payment;
import com.food.order.domain.event.publisher.DomainEventPublisher; import com.food.order.sysyem.event.publisher.DomainEventPublisher;
import com.food.order.system.domain.event.OrderCreatedEvent; import com.food.order.system.domain.event.OrderCreatedEvent;
public interface OrderCreatedPaymentRequestMessagePublisher extends DomainEventPublisher<OrderCreatedEvent> { public interface OrderCreatedPaymentRequestMessagePublisher extends DomainEventPublisher<OrderCreatedEvent> {

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.ports.output.repository; package com.food.order.sysyem.ports.output.repository;
import com.food.order.system.domain.entity.Customer; import com.food.order.system.domain.entity.Customer;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.ports.output.repository; package com.food.order.sysyem.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;

View File

@@ -1,4 +1,4 @@
package com.food.order.domain.ports.output.repository; package com.food.order.sysyem.ports.output.repository;
import com.food.order.system.domain.entity.Restaurant; import com.food.order.system.domain.entity.Restaurant;

View File

@@ -1,19 +1,20 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.dto.create.CreateOrderCommand;
import com.food.order.domain.dto.create.OrderAddress;
import com.food.order.domain.dto.create.OrderItem;
import com.food.order.domain.mapper.OrderDataMapper;
import com.food.order.domain.ports.input.service.OrderApplicationService;
import com.food.order.domain.ports.output.repository.CustomerRepository;
import com.food.order.domain.ports.output.repository.OrderRepository;
import com.food.order.domain.ports.output.repository.RestaurantRepository;
import com.food.order.domain.valueobject.*;
import com.food.order.system.domain.entity.Customer; import com.food.order.system.domain.entity.Customer;
import com.food.order.system.domain.entity.Order; import com.food.order.system.domain.entity.Order;
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.exception.OrderDomainException; import com.food.order.system.domain.exception.OrderDomainException;
import com.food.order.sysyem.dto.create.CreateOrderCommand;
import com.food.order.sysyem.dto.create.OrderAddress;
import com.food.order.sysyem.dto.create.OrderItem;
import com.food.order.sysyem.mapper.OrderDataMapper;
import com.food.order.sysyem.ports.input.service.OrderApplicationService;
import com.food.order.sysyem.ports.output.repository.CustomerRepository;
import com.food.order.sysyem.ports.output.repository.OrderRepository;
import com.food.order.sysyem.ports.output.repository.RestaurantRepository;
import com.food.order.sysyem.domain.valueobject.*;
import com.food.order.sysyem.valueobject.*;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -168,14 +169,14 @@ class OrderApplicationTest {
void testCreateOrderWrongPrice(){ void testCreateOrderWrongPrice(){
OrderDomainException exception = Assertions.assertThrows(OrderDomainException.class, OrderDomainException exception = Assertions.assertThrows(OrderDomainException.class,
() -> orderApplicationService.createOrder(createOrderCommandWrongPrice)); () -> orderApplicationService.createOrder(createOrderCommandWrongPrice));
assertEquals("Order total price is not equal to the sum of order items prices", exception.getMessage()); Assertions.assertEquals("Order total price is not equal to the sum of order items prices", exception.getMessage());
} }
@Test @Test
void testCreateOrderWrongProductPrice(){ void testCreateOrderWrongProductPrice(){
OrderDomainException exception = Assertions.assertThrows(OrderDomainException.class, OrderDomainException exception = Assertions.assertThrows(OrderDomainException.class,
() -> orderApplicationService.createOrder(createOrderCommandWrongProductPrice)); () -> orderApplicationService.createOrder(createOrderCommandWrongProductPrice));
assertEquals("Order item price is not valid", exception.getMessage()); Assertions.assertEquals("Order item price is not valid", exception.getMessage());
} }
@Test @Test
@@ -194,7 +195,7 @@ class OrderApplicationTest {
.thenReturn(Optional.of(restaurant)); .thenReturn(Optional.of(restaurant));
OrderDomainException exception = Assertions.assertThrows(OrderDomainException.class, OrderDomainException exception = Assertions.assertThrows(OrderDomainException.class,
() -> orderApplicationService.createOrder(createOrderCommand)); () -> orderApplicationService.createOrder(createOrderCommand));
assertEquals("Restaurant is not active, please try again later. Restaurant id: "+ restaurant.getId(), exception.getMessage()); Assertions.assertEquals("Restaurant is not active, please try again later. Restaurant id: "+ restaurant.getId(), exception.getMessage());
} }
} }

View File

@@ -1,18 +1,18 @@
package com.food.order.domain; package com.food.order.sysyem;
import com.food.order.domain.ports.output.message.publisher.payment.OrderCancelledPaymentRequestMessagePublisher; import com.food.order.sysyem.ports.output.message.publisher.payment.OrderCancelledPaymentRequestMessagePublisher;
import com.food.order.domain.ports.output.message.publisher.payment.OrderCreatedPaymentRequestMessagePublisher; import com.food.order.sysyem.ports.output.message.publisher.payment.OrderCreatedPaymentRequestMessagePublisher;
import com.food.order.domain.ports.output.message.publisher.restaurantapproval.OrderPaidRestaurantRequestMessagePublisher; import com.food.order.sysyem.ports.output.message.publisher.restaurantapproval.OrderPaidRestaurantRequestMessagePublisher;
import com.food.order.domain.ports.output.repository.CustomerRepository; import com.food.order.sysyem.ports.output.repository.CustomerRepository;
import com.food.order.domain.ports.output.repository.OrderRepository; import com.food.order.sysyem.ports.output.repository.OrderRepository;
import com.food.order.domain.ports.output.repository.RestaurantRepository; import com.food.order.sysyem.ports.output.repository.RestaurantRepository;
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;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@SpringBootApplication(scanBasePackages = "com.food.order.domain") @SpringBootApplication(scanBasePackages = "com.food.order.system.domain")
public class OrderTestConfiguration { public class OrderTestConfiguration {
@Bean @Bean

View File

@@ -1,12 +0,0 @@
@startuml
skinparam defaultTextAlignment center
skinparam rectangle {
BackgroundColor<<optional>> beige
BackgroundColor<<test>> lightGreen
BackgroundColor<<runtime>> lightBlue
BackgroundColor<<provided>> lightGray
}
rectangle "order-application-service" as com_food_order_order_application_service_jar
rectangle "order-core-domain" as com_food_order_order_core_domain_jar
com_food_order_order_application_service_jar -[#000000]-> com_food_order_order_core_domain_jar
@enduml

View File

@@ -1,7 +1,7 @@
package com.food.order.system.domain.entity; package com.food.order.system.domain.entity;
import com.food.order.domain.entity.AggregateRoot; import com.food.order.sysyem.entity.AggregateRoot;
import com.food.order.domain.valueobject.CustomerId; import com.food.order.sysyem.valueobject.CustomerId;
public class Customer extends AggregateRoot<CustomerId> { public class Customer extends AggregateRoot<CustomerId> {

View File

@@ -1,11 +1,11 @@
package com.food.order.system.domain.entity; package com.food.order.system.domain.entity;
import com.food.order.domain.entity.AggregateRoot; import com.food.order.sysyem.entity.AggregateRoot;
import com.food.order.domain.valueobject.*;
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 java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;

View File

@@ -1,8 +1,8 @@
package com.food.order.system.domain.entity; package com.food.order.system.domain.entity;
import com.food.order.domain.entity.BaseEntity; import com.food.order.sysyem.entity.BaseEntity;
import com.food.order.domain.valueobject.Money; import com.food.order.sysyem.valueobject.Money;
import com.food.order.domain.valueobject.OrderId; import com.food.order.sysyem.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> {

View File

@@ -1,8 +1,8 @@
package com.food.order.system.domain.entity; package com.food.order.system.domain.entity;
import com.food.order.domain.entity.BaseEntity; import com.food.order.sysyem.entity.BaseEntity;
import com.food.order.domain.valueobject.Money; import com.food.order.sysyem.valueobject.Money;
import com.food.order.domain.valueobject.ProductId; import com.food.order.sysyem.valueobject.ProductId;
public class Product extends BaseEntity<ProductId> { public class Product extends BaseEntity<ProductId> {
private String name; private String name;

View File

@@ -1,7 +1,7 @@
package com.food.order.system.domain.entity; package com.food.order.system.domain.entity;
import com.food.order.domain.entity.AggregateRoot; import com.food.order.sysyem.entity.AggregateRoot;
import com.food.order.domain.valueobject.RestaurantId; import com.food.order.sysyem.valueobject.RestaurantId;
import java.util.List; import java.util.List;

View File

@@ -1,6 +1,6 @@
package com.food.order.system.domain.event; package com.food.order.system.domain.event;
import com.food.order.domain.event.DomainEvent; import com.food.order.sysyem.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;

View File

@@ -1,6 +1,6 @@
package com.food.order.system.domain.exception; package com.food.order.system.domain.exception;
import com.food.order.domain.exception.DomainException; import com.food.order.sysyem.exception.DomainException;
public class OrderDomainException extends DomainException { public class OrderDomainException extends DomainException {

View File

@@ -1,6 +1,6 @@
package com.food.order.system.domain.exception; package com.food.order.system.domain.exception;
import com.food.order.domain.exception.DomainException; import com.food.order.sysyem.exception.DomainException;
public class OrderNotFoundException extends DomainException { public class OrderNotFoundException extends DomainException {

View File

@@ -1,8 +1,6 @@
package com.food.order.system.domain.valueobject; package com.food.order.system.domain.valueobject;
import com.food.order.domain.valueobject.BaseId; import com.food.order.sysyem.valueobject.BaseId;
import java.util.UUID;
public class OrderItemId extends BaseId<Long> { public class OrderItemId extends BaseId<Long> {

View File

@@ -1,6 +1,6 @@
package com.food.order.system.domain.valueobject; package com.food.order.system.domain.valueobject;
import com.food.order.domain.valueobject.BaseId; import com.food.order.sysyem.valueobject.BaseId;
import java.util.UUID; import java.util.UUID;

View File

@@ -1,10 +0,0 @@
@startuml
skinparam defaultTextAlignment center
skinparam rectangle {
BackgroundColor<<optional>> beige
BackgroundColor<<test>> lightGreen
BackgroundColor<<runtime>> lightBlue
BackgroundColor<<provided>> lightGray
}
rectangle "order-core-domain" as com_food_order_order_core_domain_jar
@enduml

View File

@@ -1,10 +0,0 @@
@startuml
skinparam defaultTextAlignment center
skinparam rectangle {
BackgroundColor<<optional>> beige
BackgroundColor<<test>> lightGreen
BackgroundColor<<runtime>> lightBlue
BackgroundColor<<provided>> lightGray
}
rectangle "order-domain" as com_food_order_order_domain_pom
@enduml

View File

@@ -19,6 +19,21 @@
<groupId>com.food.order</groupId> <groupId>com.food.order</groupId>
<artifactId>order-application-service</artifactId> <artifactId>order-application-service</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-producer</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-consumer</artifactId>
</dependency>
<dependency>
<groupId>com.food.order</groupId>
<artifactId>kafka-model</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -0,0 +1,54 @@
package com.food.order.system.order.messaging.listener.kafka;
import com.food.order.sysyem.ports.input.message.listener.payment.PaymentResponseMessageListener;
import com.food.order.system.kafka.consumer.KafkaConsumer;
import com.food.order.system.order.messaging.mapper.OrderMessagingDataMapper;
import com.food.ordering.system.kafka.order.avro.model.PaymentResponseAvroModel;
import com.food.ordering.system.kafka.order.avro.model.PaymentStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
@RequiredArgsConstructor
public class PaymentResponseKafkaListener implements KafkaConsumer<PaymentResponseAvroModel> {
private final OrderMessagingDataMapper orderMessagingDataMapper;
private final PaymentResponseMessageListener paymentResponseMessageListener;
@Override
@KafkaListener(
id = "${kafka-consumer-config.payment-consumer-group-id}",
topics = "${order-service.payment-response-topic-name}"
)
public void receive(@Payload List<PaymentResponseAvroModel> messages,
@Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) List<String> keys,
@Header(KafkaHeaders.RECEIVED_PARTITION_ID) List<Integer> partitions,
@Header(KafkaHeaders.OFFSET) List<Long> offSets) {
log.info("{} number of payment responses received with keys : {} , partitions : {} , offsets : {}",
messages.size(), keys, partitions, offSets);
messages.forEach(message -> {
if (PaymentStatus.COMPLETED.equals(message.getPaymentStatus())) {
log.info("Processing successful payment response for order id: {}", message.getOrderId());
paymentResponseMessageListener.paymentCompleted(orderMessagingDataMapper.
paymentResponseAvroModelToPaymentResponse(message));
}
else if (PaymentStatus.FAILED.equals(message.getPaymentStatus()) ||
PaymentStatus.CANCELLED.equals(message.getPaymentStatus())) {
log.info("Processing failed payment response for order id: {}", message.getOrderId());
paymentResponseMessageListener.paymentCancelled(orderMessagingDataMapper.
paymentResponseAvroModelToPaymentResponse(message));
}
});
}
}

View File

@@ -0,0 +1,52 @@
package com.food.order.system.order.messaging.listener.kafka;
import com.food.order.sysyem.ports.input.message.listener.restaurantapproval.RestaurantApprovalResponseMessageListener;
import com.food.order.system.kafka.consumer.KafkaConsumer;
import com.food.order.system.order.messaging.mapper.OrderMessagingDataMapper;
import com.food.ordering.system.kafka.order.avro.model.OrderApprovalStatus;
import com.food.ordering.system.kafka.order.avro.model.RestaurantApprovalResponseAvroModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@RequiredArgsConstructor
@Component
public class RestaurantApprovalResponseKafkaListener implements KafkaConsumer<RestaurantApprovalResponseAvroModel> {
private final OrderMessagingDataMapper orderMessagingDataMapper;
private final RestaurantApprovalResponseMessageListener responseMessageListener;
@Override
@KafkaListener(
id = "${kafka-consumer-config.restaurant-approval-consumer-group-id}",
topics = "${order-service.restaurant-approval-response-topic-name}"
)
public void receive(@Payload List<RestaurantApprovalResponseAvroModel> messages,
@Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) List<String> keys,
@Header(KafkaHeaders.RECEIVED_PARTITION_ID) List<Integer> partitions,
@Header(KafkaHeaders.OFFSET) List<Long> offSets) {
log.info("{} number of restaurant approval responses received with keys : {} , partitions : {} , offsets : {}",
messages.size(), keys, partitions, offSets);
messages.forEach(message -> {
if (message.getOrderApprovalStatus().equals(OrderApprovalStatus.APPROVED)) {
log.info("Processing successful restaurant approval response for order id: {}", message.getOrderId());
responseMessageListener.orderApproved(orderMessagingDataMapper.
restaurantApprovalResponseAvroModelToRestaurantApprovalResponse(message));
}
else if (message.getOrderApprovalStatus().equals(OrderApprovalStatus.REJECTED)) {
log.info("Processing failed restaurant approval response for order id: {}", message.getOrderId());
responseMessageListener.orderRejected(orderMessagingDataMapper.
restaurantApprovalResponseAvroModelToRestaurantApprovalResponse(message));
}
});
}
}

View File

@@ -0,0 +1,90 @@
package com.food.order.system.order.messaging.mapper;
import com.food.order.sysyem.dto.message.PaymentResponse;
import com.food.order.sysyem.dto.message.RestaurantApprovalResponse;
import com.food.order.sysyem.valueobject.OrderApprovalStatus;
import com.food.order.sysyem.valueobject.PaymentStatus;
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.ordering.system.kafka.order.avro.model.*;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Component
public class OrderMessagingDataMapper {
public PaymentRequestAvroModel orderCreatedEventToPaymenRequestAvroModel(OrderCreatedEvent orderCreatedEvent) {
var order = orderCreatedEvent.getOrder();
return PaymentRequestAvroModel.newBuilder()
.setOrderId(order.getId().getValue().toString())
.setSagaId("")
.setCustomerId(order.getCustomerId().getValue().toString())
.setId(UUID.randomUUID().toString())
.setPrice(order.getPrice().getAmount())
.setCreatedAt(orderCreatedEvent.getCreatedAt().toInstant())
.setPaymentOrderStatus(PaymentOrderStatus.PENDING)
.build();
}
public PaymentRequestAvroModel orderCancelledEventToPaymenRequestAvroModel(OrderCancelledEvent orderCancelledEvent) {
var order = orderCancelledEvent.getOrder();
return PaymentRequestAvroModel.newBuilder()
.setOrderId(order.getId().getValue().toString())
.setSagaId("")
.setCustomerId(order.getCustomerId().getValue().toString())
.setId(UUID.randomUUID().toString())
.setPrice(order.getPrice().getAmount())
.setCreatedAt(orderCancelledEvent.getCreatedAt().toInstant())
.setPaymentOrderStatus(PaymentOrderStatus.CANCELLED)
.build();
}
public RestaurantApprovalRequestAvroModel orderPaidEventToRestaurantApprovalRequestAvroModel(OrderPaidEvent event) {
var order = event.getOrder();
return RestaurantApprovalRequestAvroModel.newBuilder()
.setOrderId(order.getId().getValue().toString())
.setRestaurantId(order.getRestaurantId().getValue().toString())
.setProducts(order.getItems().stream()
.map(item -> com.food.ordering.system.kafka.order.avro.model.Product.newBuilder()
.setId(item.getId().getValue().toString())
.setQuantity(item.getQuantity())
.build())
.toList())
.setId(UUID.randomUUID().toString())
.setSagaId("")
.setPrice(order.getPrice().getAmount())
.setCreatedAt(event.getCreatedAt().toInstant())
.setRestaurantOrderStatus(RestaurantOrderStatus.PAID)
.build();
}
public PaymentResponse paymentResponseAvroModelToPaymentResponse(PaymentResponseAvroModel message) {
return PaymentResponse.builder()
.orderId(message.getOrderId())
.sagaId(message.getSagaId())
.paymentId(message.getPaymentId())
.customerId(message.getCustomerId())
.orderId(message.getOrderId())
.price(message.getPrice())
.createdAt(message.getCreatedAt())
.paymentStatus(PaymentStatus.valueOf(message.getPaymentStatus().name()))
.failureMessages(message.getFailureMessages())
.build();
}
public RestaurantApprovalResponse restaurantApprovalResponseAvroModelToRestaurantApprovalResponse(RestaurantApprovalResponseAvroModel message) {
return RestaurantApprovalResponse.builder()
.orderId(message.getOrderId())
.sagaId(message.getSagaId())
.restaurantId(message.getRestaurantId())
.id(message.getId())
.sagaId(message.getSagaId())
.createdAt(message.getCreatedAt())
.orderApprovalStatus(OrderApprovalStatus.valueOf(message.getOrderApprovalStatus().name()))
.failureMessages(message.getFailureMessages())
.build();
}
}

View File

@@ -0,0 +1,53 @@
package com.food.order.system.order.messaging.publisher.kafka;
import com.food.order.sysyem.config.OrderServiceConfigData;
import com.food.order.sysyem.ports.output.message.publisher.payment.OrderCancelledPaymentRequestMessagePublisher;
import com.food.order.system.domain.event.OrderCancelledEvent;
import com.food.order.system.kafka.producer.service.KafkaProducer;
import com.food.order.system.order.messaging.mapper.OrderMessagingDataMapper;
import com.food.ordering.system.kafka.order.avro.model.PaymentRequestAvroModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@RequiredArgsConstructor
@Slf4j
@Component
public class CancelOrderKafkaMessagePublisher implements OrderCancelledPaymentRequestMessagePublisher {
private final OrderMessagingDataMapper orderMessagingDataMapper;
private final OrderServiceConfigData configData;
private final KafkaProducer<String, PaymentRequestAvroModel> kafkaProducer;
private final OrderKafkaMessageHelper orderKafkaMessageHelper;
@Override
public void publish(OrderCancelledEvent event) {
var orderId = event.getOrder().getId().getValue().toString();
log.info("Publishing order cancel event for order id: {}", orderId);
try{
var paymentRequestAvroModel =
orderMessagingDataMapper.orderCancelledEventToPaymenRequestAvroModel(event);
kafkaProducer.send(
configData.getPaymentRequestTopicName(),
orderId,
paymentRequestAvroModel,
orderKafkaMessageHelper.getKafkaCallBack(configData.getPaymentRequestTopicName()
,paymentRequestAvroModel,
orderId,
"PaymentRequestAvroModel"));
log.info("Published order cancel event for order id: {}", orderId);
}
catch(Exception e){
log.error("Error publishing order cancel event for order id: {}", orderId, e);
}
}
}

View File

@@ -0,0 +1,51 @@
package com.food.order.system.order.messaging.publisher.kafka;
import com.food.order.sysyem.config.OrderServiceConfigData;
import com.food.order.sysyem.ports.output.message.publisher.payment.OrderCreatedPaymentRequestMessagePublisher;
import com.food.order.system.domain.event.OrderCreatedEvent;
import com.food.order.system.kafka.producer.service.KafkaProducer;
import com.food.order.system.order.messaging.mapper.OrderMessagingDataMapper;
import com.food.ordering.system.kafka.order.avro.model.PaymentRequestAvroModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
public class CreateOrderKafkaMessagePublisher implements OrderCreatedPaymentRequestMessagePublisher {
private final OrderMessagingDataMapper orderMessagingDataMapper;
private final OrderServiceConfigData configData;
private final KafkaProducer<String, PaymentRequestAvroModel> kafkaProducer;
private final OrderKafkaMessageHelper orderKafkaMessageHelper;
@Override
public void publish(OrderCreatedEvent event) {
var orderId = event.getOrder().getId().getValue().toString();
log.info("Publishing order created event for order id: {}", orderId);
try{
var paymentRequestAvroModel =
orderMessagingDataMapper.orderCreatedEventToPaymenRequestAvroModel(event);
kafkaProducer.send(
configData.getPaymentRequestTopicName(),
orderId,
paymentRequestAvroModel,
orderKafkaMessageHelper.getKafkaCallBack(configData.getPaymentRequestTopicName(),
paymentRequestAvroModel,
orderId,
"PaymentRequestAvroModel"));
log.info("Published order created event for order id: {}", orderId);
}
catch(Exception e){
log.error("Error publishing order created event for order id: {}", orderId, e);
}
}
}

View File

@@ -0,0 +1,34 @@
package com.food.order.system.order.messaging.publisher.kafka;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.springframework.kafka.support.SendResult;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFutureCallback;
@Component
@Slf4j
public class OrderKafkaMessageHelper {
public <T> ListenableFutureCallback<SendResult<String, T>> getKafkaCallBack
(String responseTopicName, T requestAvroModel,String orderId, String requestAvroModelName) {
return new ListenableFutureCallback<SendResult<String , T>>() {
@Override
public void onFailure(Throwable ex) {
log.error("Error while sending " + requestAvroModelName +
" to " + responseTopicName + " for orderId " + orderId, ex);
}
@Override
public void onSuccess(SendResult<String, T> result) {
RecordMetadata recordMetadata = result.getRecordMetadata();
log.info("Received successful response from kafka for order id : {} Topic : {} Partition : {} , Offset : {} , Timestamp : {}",
orderId,
recordMetadata.topic(),
recordMetadata.partition(),
recordMetadata.offset(),
recordMetadata.timestamp());
}
};
}
}

View File

@@ -0,0 +1,46 @@
package com.food.order.system.order.messaging.publisher.kafka;
import com.food.order.sysyem.config.OrderServiceConfigData;
import com.food.order.sysyem.ports.output.message.publisher.restaurantapproval.OrderPaidRestaurantRequestMessagePublisher;
import com.food.order.system.domain.event.OrderPaidEvent;
import com.food.order.system.kafka.producer.service.KafkaProducer;
import com.food.order.system.order.messaging.mapper.OrderMessagingDataMapper;
import com.food.ordering.system.kafka.order.avro.model.RestaurantApprovalRequestAvroModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
public class PayOrderKafkaMessagePublisher implements OrderPaidRestaurantRequestMessagePublisher {
private final OrderMessagingDataMapper orderMessagingDataMapper;
private final OrderServiceConfigData configData;
private final KafkaProducer<String, RestaurantApprovalRequestAvroModel> kafkaProducer;
private final OrderKafkaMessageHelper orderKafkaMessageHelper;
@Override
public void publish(OrderPaidEvent event) {
var orderId = event.getOrder().getId().getValue().toString();
try {
var message =
orderMessagingDataMapper.orderPaidEventToRestaurantApprovalRequestAvroModel(event);
kafkaProducer.send(configData.getRestaurantApprovalRequestTopicName(),
orderId,
message,
orderKafkaMessageHelper.getKafkaCallBack(configData.getRestaurantApprovalRequestTopicName(), message,
orderId,
"RestaurantApprovalRequestAvroModel"));
log.info("Published order paid event for order id: {}", orderId);
}
catch (Exception e) {
log.error("Error publishing order paid event for order id: {}", orderId, e);
}
}
}

View File

@@ -67,25 +67,25 @@
<dependency> <dependency>
<groupId>com.food.order</groupId> <groupId>com.food.order</groupId>
<artifactId>kafka-producer</artifactId> <artifactId>kafka-producer</artifactId>
<version>1.0-SNAPSHOT</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.food.order</groupId> <groupId>com.food.order</groupId>
<artifactId>kafka-consumer</artifactId> <artifactId>kafka-consumer</artifactId>
<version>1.0-SNAPSHOT</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.food.order</groupId> <groupId>com.food.order</groupId>
<artifactId>kafka-model</artifactId> <artifactId>kafka-model</artifactId>
<version>1.0-SNAPSHOT</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.food.order</groupId> <groupId>com.food.order</groupId>
<artifactId>kafka-config</artifactId> <artifactId>kafka-config</artifactId>
<version>1.0-SNAPSHOT</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -1,22 +0,0 @@
@startuml
skinparam defaultTextAlignment center
skinparam rectangle {
BackgroundColor<<optional>> beige
BackgroundColor<<test>> lightGreen
BackgroundColor<<runtime>> lightBlue
BackgroundColor<<provided>> lightGray
}
rectangle "order-application-service" as com_food_order_order_application_service_jar_compile
rectangle "order-core-domain" as com_food_order_order_core_domain_jar_compile
rectangle "order-app" as com_food_order_order_app_jar_compile
rectangle "order-data-access" as com_food_order_order_data_access_jar_compile
rectangle "order-messaging" as com_food_order_order_messaging_jar_compile
rectangle "order-container" as com_food_order_order_container_jar_compile
com_food_order_order_application_service_jar_compile -[#000000]-> com_food_order_order_core_domain_jar_compile
com_food_order_order_app_jar_compile -[#000000]-> com_food_order_order_application_service_jar_compile
com_food_order_order_data_access_jar_compile -[#000000]-> com_food_order_order_application_service_jar_compile
com_food_order_order_messaging_jar_compile -[#000000]-> com_food_order_order_application_service_jar_compile
com_food_order_order_container_jar_compile -[#000000]-> com_food_order_order_app_jar_compile
com_food_order_order_container_jar_compile -[#000000]-> com_food_order_order_data_access_jar_compile
com_food_order_order_container_jar_compile -[#000000]-> com_food_order_order_messaging_jar_compile
@enduml