diff --git a/.gitignore b/.gitignore index 5eac309..11ddca2 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ build/ !**/src/test/**/build/ ### VS Code ### -.vscode/ \ No newline at end of file +.vscode/ +/infrastructure/docker-compose/volumes/ diff --git a/common/common-domain/src/main/java/com/food/order/sysyem/DomainConstants.java b/common/common-domain/src/main/java/com/food/order/sysyem/DomainConstants.java new file mode 100644 index 0000000..8327e68 --- /dev/null +++ b/common/common-domain/src/main/java/com/food/order/sysyem/DomainConstants.java @@ -0,0 +1,10 @@ +package com.food.order.sysyem; + +public class DomainConstants { + + private DomainConstants() { + } + + public static final String UTC = "UTC"; + +} diff --git a/common/common-domain/src/main/java/com/food/order/sysyem/event/DomainEvent.java b/common/common-domain/src/main/java/com/food/order/sysyem/event/DomainEvent.java index ab1abd7..b05b464 100644 --- a/common/common-domain/src/main/java/com/food/order/sysyem/event/DomainEvent.java +++ b/common/common-domain/src/main/java/com/food/order/sysyem/event/DomainEvent.java @@ -4,5 +4,6 @@ package com.food.order.sysyem.event; // Base Domain Event Generic Class public interface DomainEvent { + void fire(); } diff --git a/common/common-domain/src/main/java/com/food/order/sysyem/valueobject/Money.java b/common/common-domain/src/main/java/com/food/order/sysyem/valueobject/Money.java index 3821131..6098945 100644 --- a/common/common-domain/src/main/java/com/food/order/sysyem/valueobject/Money.java +++ b/common/common-domain/src/main/java/com/food/order/sysyem/valueobject/Money.java @@ -28,7 +28,7 @@ public class Money { this.amount.compareTo(other.amount) > 0; } - public Money substract(Money other) { + public Money subtract(Money other) { return new Money(setScale(this.amount.subtract(other.getAmount()))); } diff --git a/common/common-domain/src/main/java/com/food/order/sysyem/valueobject/PaymentOrderStatus.java b/common/common-domain/src/main/java/com/food/order/sysyem/valueobject/PaymentOrderStatus.java new file mode 100644 index 0000000..b777250 --- /dev/null +++ b/common/common-domain/src/main/java/com/food/order/sysyem/valueobject/PaymentOrderStatus.java @@ -0,0 +1,6 @@ +package com.food.order.sysyem.valueobject; + +public enum PaymentOrderStatus { + PENDING, + CANCELLED +} diff --git a/infrastructure/docker-compose/.env b/infrastructure/docker-compose/.env index 4958bd5..d45e7d7 100644 --- a/infrastructure/docker-compose/.env +++ b/infrastructure/docker-compose/.env @@ -1,3 +1,3 @@ KAFKA_VERSION=7.0.1 GLOBAL_NETWORK=food-order-system -GROUP_ID=com.food-order-system +GROUP_ID=com.food.order diff --git a/infrastructure/docker-compose/init_kafka.yml b/infrastructure/docker-compose/init_kafka.yml index 4e91e52..db971ec 100644 --- a/infrastructure/docker-compose/init_kafka.yml +++ b/infrastructure/docker-compose/init_kafka.yml @@ -9,16 +9,16 @@ services: kafka-topics --bootstrap-server kafka-broker-1:9092 --list echo -e 'Deleting kafka topics' - kafka-topics --bootstrap-server kafka-broker-1:9092 --topic payment-request --delete --if-exists - kafka-topics --bootstrap-server kafka-broker-1:9092 --topic payment-response --delete --if-exists - kafka-topics --bootstrap-server kafka-broker-1:9092 --topic restaurant-approval-request --delete --if-exists - kafka-topics --bootstrap-server kafka-broker-1:9092 --topic restaurant-approval-response --delete --if-exists + kafka-topics --bootstrap-server kafka-broker-1:9092 --topic payment-request-value --delete --if-exists + kafka-topics --bootstrap-server kafka-broker-1:9092 --topic payment-response-value --delete --if-exists + kafka-topics --bootstrap-server kafka-broker-1:9092 --topic restaurant-approval-request-value --delete --if-exists + kafka-topics --bootstrap-server kafka-broker-1:9092 --topic restaurant-approval-response-value --delete --if-exists echo -e 'Creating kafka topics' - kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic payment-request --replication-factor 3 --partitions 3 - kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic payment-response --replication-factor 3 --partitions 3 - kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic restaurant-approval-request --replication-factor 3 --partitions 3 - kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic restaurant-approval-response --replication-factor 3 --partitions 3 + kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic payment-request-value --replication-factor 3 --partitions 3 + kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic payment-response-value --replication-factor 3 --partitions 3 + kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic restaurant-approval-request-value --replication-factor 3 --partitions 3 + kafka-topics --bootstrap-server kafka-broker-1:9092 --create --if-not-exists --topic restaurant-approval-response-value --replication-factor 3 --partitions 3 echo -e 'Successfully created the following topics:' diff --git a/infrastructure/kafka/kafka-producer/src/main/java/com/food/order/system/kafka/producer/service/impl/KafkaProducerImpl.java b/infrastructure/kafka/kafka-producer/src/main/java/com/food/order/system/kafka/producer/service/impl/KafkaProducerImpl.java index cd818e7..4fca267 100644 --- a/infrastructure/kafka/kafka-producer/src/main/java/com/food/order/system/kafka/producer/service/impl/KafkaProducerImpl.java +++ b/infrastructure/kafka/kafka-producer/src/main/java/com/food/order/system/kafka/producer/service/impl/KafkaProducerImpl.java @@ -1,48 +1,52 @@ package com.food.order.system.kafka.producer.service.impl; -import com.food.order.system.kafka.producer.exception.KafkaProducerException; import com.food.order.system.kafka.producer.service.KafkaProducer; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.avro.specific.SpecificRecordBase; -import org.springframework.kafka.KafkaException; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.support.SendResult; import org.springframework.stereotype.Component; -import org.springframework.util.concurrent.ListenableFuture; import org.springframework.util.concurrent.ListenableFutureCallback; import javax.annotation.PreDestroy; import java.io.Serializable; +import java.util.Objects; -@Slf4j @Component +@RequiredArgsConstructor +@Slf4j public class KafkaProducerImpl implements KafkaProducer { private final KafkaTemplate kafkaTemplate; - public KafkaProducerImpl(KafkaTemplate kafkaTemplate) { - this.kafkaTemplate = kafkaTemplate; - } - @Override public void send(String topicName, K key, V message, ListenableFutureCallback> callback) { - log.info("Sending message={} to topic={}", message, topicName); - try { - ListenableFuture> kafkaResultFuture = kafkaTemplate.send(topicName, key, message); - kafkaResultFuture.addCallback(callback); - } catch (KafkaException e) { - log.error("Error on kafka producer with key: {}, message: {} and exception: {}", key, message, - e.getMessage()); - throw new KafkaProducerException("Error on kafka producer with key: " + key + " and message: " + message); - } + log.info("Sending message to topic: {}, also message {}", topicName,message); + kafkaTemplate.send(topicName, key, message) + .addCallback(new ListenableFutureCallback<>() { + @Override + public void onFailure(Throwable ex) { + log.error("Error sending message to topic: {}, also message {}", topicName, message, ex); + callback.onFailure(ex); + } + + @Override + public void onSuccess(SendResult result) { + log.info("Message sent to topic: {}, also message {}", topicName, message); + callback.onSuccess(result); + } + }); } @PreDestroy - public void close() { - if (kafkaTemplate != null) { - log.info("Closing kafka producer!"); + public void destroy() { + log.info("KafkaProducerImpl is being destroyed"); + if (Objects.nonNull(kafkaTemplate)) { kafkaTemplate.destroy(); } } + + } diff --git a/order-service/order-container/src/main/resources/application.yml b/order-service/order-container/src/main/resources/application.yml index 07abc06..fc6e593 100644 --- a/order-service/order-container/src/main/resources/application.yml +++ b/order-service/order-container/src/main/resources/application.yml @@ -5,10 +5,10 @@ logging: 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 + payment-request-topic-name: payment-request-value + payment-response-topic-name: payment-response-value + restaurant-approval-request-topic-name: restaurant-approval-request-value + restaurant-approval-response-topic-name: restaurant-approval-response-value spring: jpa: diff --git a/order-service/order-domain/order-application-service/src/main/java/com/food/order/sysyem/OrderCreateHelper.java b/order-service/order-domain/order-application-service/src/main/java/com/food/order/sysyem/OrderCreateHelper.java index 779c885..53a3840 100644 --- a/order-service/order-domain/order-application-service/src/main/java/com/food/order/sysyem/OrderCreateHelper.java +++ b/order-service/order-domain/order-application-service/src/main/java/com/food/order/sysyem/OrderCreateHelper.java @@ -1,6 +1,7 @@ package com.food.order.sysyem; import com.food.order.sysyem.dto.create.CreateOrderCommand; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; import com.food.order.sysyem.mapper.OrderDataMapper; import com.food.order.sysyem.ports.output.repository.CustomerRepository; import com.food.order.sysyem.ports.output.repository.OrderRepository; @@ -27,6 +28,7 @@ public class OrderCreateHelper { private final CustomerRepository customerRepository; private final RestaurantRepository restaurantRepository; private final OrderDataMapper orderDataMapper; + private final DomainEventPublisher publisher; @Transactional public OrderCreatedEvent persistOrder(CreateOrderCommand createOrderCommand) { @@ -34,7 +36,7 @@ public class OrderCreateHelper { checkCustomer(createOrderCommand.customerId()); Restaurant restaurant = checkRestaurant(createOrderCommand); var order = orderDataMapper.createOrderCommandToOrder(createOrderCommand); - var createdEventOrder = orderDomainService.validateAndInitiateOrder(order, restaurant); + var createdEventOrder = orderDomainService.validateAndInitiateOrder(order, restaurant,publisher); saveOrder(order); log.info("Created Order Event : {}", createdEventOrder); return createdEventOrder; diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCancelledEvent.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCancelledEvent.java index 6e8f7b5..7970c1e 100644 --- a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCancelledEvent.java +++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCancelledEvent.java @@ -1,12 +1,22 @@ package com.food.order.system.domain.event; import com.food.order.system.domain.entity.Order; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; import java.time.ZonedDateTime; public class OrderCancelledEvent extends OrderEvent { - public OrderCancelledEvent(Order order, ZonedDateTime utc) { + private final DomainEventPublisher publisher; + + + public OrderCancelledEvent(Order order, ZonedDateTime utc, DomainEventPublisher publisher) { super(order, utc); + this.publisher = publisher; + } + + @Override + public void fire() { + publisher.publish(this); } } diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCreatedEvent.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCreatedEvent.java index 620f5c1..b0f98da 100644 --- a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCreatedEvent.java +++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderCreatedEvent.java @@ -1,11 +1,20 @@ package com.food.order.system.domain.event; import com.food.order.system.domain.entity.Order; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; import java.time.ZonedDateTime; public class OrderCreatedEvent extends OrderEvent { - public OrderCreatedEvent(Order order, ZonedDateTime createdAt) { + + private final DomainEventPublisher publisher; + public OrderCreatedEvent(Order order, ZonedDateTime createdAt, DomainEventPublisher publisher) { super(order, createdAt); + this.publisher = publisher; + } + + @Override + public void fire() { + publisher.publish(this); } } diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderPaidEvent.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderPaidEvent.java index 6467567..6dfaa2d 100644 --- a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderPaidEvent.java +++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/event/OrderPaidEvent.java @@ -1,13 +1,21 @@ package com.food.order.system.domain.event; import com.food.order.system.domain.entity.Order; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; import java.time.ZonedDateTime; public class OrderPaidEvent extends OrderEvent { - public OrderPaidEvent(Order order, ZonedDateTime utc) { + private final DomainEventPublisher publisher; + + public OrderPaidEvent(Order order, ZonedDateTime utc, DomainEventPublisher publisher) { super(order, utc); + this.publisher = publisher; } + @Override + public void fire() { + publisher.publish(this); + } } diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/OrderDomainService.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/OrderDomainService.java index 6de2853..e514266 100644 --- a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/OrderDomainService.java +++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/OrderDomainService.java @@ -5,18 +5,19 @@ import com.food.order.system.domain.entity.Restaurant; import com.food.order.system.domain.event.OrderCancelledEvent; import com.food.order.system.domain.event.OrderCreatedEvent; import com.food.order.system.domain.event.OrderPaidEvent; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; import java.util.List; public interface OrderDomainService { - OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant); + OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant, DomainEventPublisher publisher); - OrderPaidEvent payOrder(Order order); + OrderPaidEvent payOrder(Order order,DomainEventPublisher publisher); void approve(Order order); - OrderCancelledEvent cancelOrderPayment(Order order, List failureMessages); + OrderCancelledEvent cancelOrderPayment(Order order, List failureMessages,DomainEventPublisher publisher); void cancelOrder(Order order, List failureMessages); diff --git a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/impl/OrderDomainServiceImpl.java b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/impl/OrderDomainServiceImpl.java index 0f9e55c..418d245 100644 --- a/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/impl/OrderDomainServiceImpl.java +++ b/order-service/order-domain/order-core-domain/src/main/java/com/food/order/system/domain/service/impl/OrderDomainServiceImpl.java @@ -7,6 +7,7 @@ import com.food.order.system.domain.event.OrderCreatedEvent; import com.food.order.system.domain.event.OrderPaidEvent; import com.food.order.system.domain.exception.OrderDomainException; import com.food.order.system.domain.service.OrderDomainService; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; import lombok.extern.slf4j.Slf4j; import java.time.ZoneId; @@ -19,13 +20,14 @@ public class OrderDomainServiceImpl implements OrderDomainService { private static final String UTC = "UTC"; @Override - public OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant) { + public OrderCreatedEvent validateAndInitiateOrder(Order order, Restaurant restaurant, + DomainEventPublisher publisher) { validateRestaurant(restaurant); setOrderProductInformation(order,restaurant); order.validateOrder(); order.initializeOrder(); log.info("Order with id {} initialize successfully", order.getId().getValue()); - return new OrderCreatedEvent(order, ZonedDateTime.now(ZoneId.of(UTC))); + return new OrderCreatedEvent(order, ZonedDateTime.now(ZoneId.of(UTC)),publisher); } private void setOrderProductInformation(Order order, Restaurant restaurant) { @@ -46,10 +48,10 @@ public class OrderDomainServiceImpl implements OrderDomainService { } @Override - public OrderPaidEvent payOrder(Order order) { + public OrderPaidEvent payOrder(Order order, DomainEventPublisher publisher) { order.pay(); log.info("Order with id {} paid successfully", order.getId().getValue()); - return new OrderPaidEvent(order, ZonedDateTime.now(ZoneId.of(UTC))); + return new OrderPaidEvent(order, ZonedDateTime.now(ZoneId.of(UTC)),publisher); } @Override @@ -59,10 +61,11 @@ public class OrderDomainServiceImpl implements OrderDomainService { } @Override - public OrderCancelledEvent cancelOrderPayment(Order order, List failureMessages) { + public OrderCancelledEvent cancelOrderPayment(Order order, List failureMessages, + DomainEventPublisher publisher) { order.initCancel(failureMessages); log.info("Order with id {} cancelled successfully", order.getId().getValue()); - return new OrderCancelledEvent(order, ZonedDateTime.now(ZoneId.of(UTC))); + return new OrderCancelledEvent(order, ZonedDateTime.now(ZoneId.of(UTC)),publisher); } @Override diff --git a/payment-service/payment-container/pom.xml b/payment-service/payment-container/pom.xml new file mode 100644 index 0000000..be3eaf1 --- /dev/null +++ b/payment-service/payment-container/pom.xml @@ -0,0 +1,15 @@ + + + + payment-service + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + payment-container + + + \ No newline at end of file diff --git a/payment-service/payment-dataaccess/pom.xml b/payment-service/payment-dataaccess/pom.xml new file mode 100644 index 0000000..021c372 --- /dev/null +++ b/payment-service/payment-dataaccess/pom.xml @@ -0,0 +1,34 @@ + + + + payment-service + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + payment-dataaccess + + + + + com.food.order + payment-application-service + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + org.postgresql + postgresql + + + + + \ No newline at end of file diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/adapter/CreditEntryRepositoryImpl.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/adapter/CreditEntryRepositoryImpl.java new file mode 100644 index 0000000..a04c5a9 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/adapter/CreditEntryRepositoryImpl.java @@ -0,0 +1,38 @@ +package com.food.order.system.payment.data.access.creditentry.adapter; + + +import com.food.order.system.payment.application.service.ports.output.repository.CreditEntryRepository; +import com.food.order.system.payment.data.access.creditentry.mapper.CreditEntryDataAccessMapper; +import com.food.order.system.payment.data.access.creditentry.repository.CreditEntryJpaRepository; +import com.food.order.system.payment.service.domain.entity.CreditEntry; +import com.food.order.sysyem.valueobject.CustomerId; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +public class CreditEntryRepositoryImpl implements CreditEntryRepository { + + private final CreditEntryJpaRepository creditEntryJpaRepository; + private final CreditEntryDataAccessMapper creditEntryDataAccessMapper; + + public CreditEntryRepositoryImpl(CreditEntryJpaRepository creditEntryJpaRepository, + CreditEntryDataAccessMapper creditEntryDataAccessMapper) { + this.creditEntryJpaRepository = creditEntryJpaRepository; + this.creditEntryDataAccessMapper = creditEntryDataAccessMapper; + } + + @Override + public CreditEntry save(CreditEntry creditEntry) { + return creditEntryDataAccessMapper + .creditEntryEntityToCreditEntry(creditEntryJpaRepository + .save(creditEntryDataAccessMapper.creditEntryToCreditEntryEntity(creditEntry))); + } + + @Override + public Optional findByCustomerId(CustomerId customerId) { + return creditEntryJpaRepository + .findByCustomerId(customerId.getValue()) + .map(creditEntryDataAccessMapper::creditEntryEntityToCreditEntry); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/entity/CreditEntryEntity.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/entity/CreditEntryEntity.java new file mode 100644 index 0000000..da93927 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/entity/CreditEntryEntity.java @@ -0,0 +1,38 @@ +package com.food.order.system.payment.data.access.creditentry.entity; + +import lombok.*; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.math.BigDecimal; +import java.util.Objects; +import java.util.UUID; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "credit_entry") +@Entity +public class CreditEntryEntity { + + @Id + private UUID id; + private UUID customerId; + private BigDecimal totalCreditAmount; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CreditEntryEntity that = (CreditEntryEntity) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/exception/CreditEntryDataaccessException.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/exception/CreditEntryDataaccessException.java new file mode 100644 index 0000000..b8e70f4 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/exception/CreditEntryDataaccessException.java @@ -0,0 +1,8 @@ +package com.food.order.system.payment.data.access.creditentry.exception; + +public class CreditEntryDataaccessException extends RuntimeException { + + public CreditEntryDataaccessException(String message) { + super(message); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/mapper/CreditEntryDataAccessMapper.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/mapper/CreditEntryDataAccessMapper.java new file mode 100644 index 0000000..ff37152 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/mapper/CreditEntryDataAccessMapper.java @@ -0,0 +1,30 @@ +package com.food.order.system.payment.data.access.creditentry.mapper; + + +import com.food.order.system.payment.data.access.creditentry.entity.CreditEntryEntity; +import com.food.order.system.payment.service.domain.entity.CreditEntry; +import com.food.order.system.payment.service.domain.valueobject.CreditEntryId; +import com.food.order.sysyem.valueobject.CustomerId; +import com.food.order.sysyem.valueobject.Money; +import org.springframework.stereotype.Component; + +@Component +public class CreditEntryDataAccessMapper { + + public CreditEntry creditEntryEntityToCreditEntry(CreditEntryEntity creditEntryEntity) { + return CreditEntry.builder() + .id(new CreditEntryId(creditEntryEntity.getId())) + .customerId(new CustomerId(creditEntryEntity.getCustomerId())) + .totalCreditAmount(new Money(creditEntryEntity.getTotalCreditAmount())) + .build(); + } + + public CreditEntryEntity creditEntryToCreditEntryEntity(CreditEntry creditEntry) { + return CreditEntryEntity.builder() + .id(creditEntry.getId().getValue()) + .customerId(creditEntry.getCustomerId().getValue()) + .totalCreditAmount(creditEntry.getTotalCreditAmount().getAmount()) + .build(); + } + +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/repository/CreditEntryJpaRepository.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/repository/CreditEntryJpaRepository.java new file mode 100644 index 0000000..8f1317f --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/creditentry/repository/CreditEntryJpaRepository.java @@ -0,0 +1,16 @@ +package com.food.order.system.payment.data.access.creditentry.repository; + +import com.food.order.system.payment.data.access.creditentry.entity.CreditEntryEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface CreditEntryJpaRepository extends JpaRepository { + + Optional findByCustomerId(UUID customerId); + + +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/adapter/CreditHistoryRepositoryImpl.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/adapter/CreditHistoryRepositoryImpl.java new file mode 100644 index 0000000..d100eaf --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/adapter/CreditHistoryRepositoryImpl.java @@ -0,0 +1,44 @@ +package com.food.order.system.payment.data.access.credithistory.adapter; + + +import com.food.order.system.payment.application.service.ports.output.repository.CreditHistoryRepository; +import com.food.order.system.payment.data.access.credithistory.entity.CreditHistoryEntity; +import com.food.order.system.payment.data.access.credithistory.mapper.CreditHistoryDataAccessMapper; +import com.food.order.system.payment.data.access.credithistory.repository.CreditHistoryJpaRepository; +import com.food.order.system.payment.service.domain.entity.CreditHistory; +import com.food.order.sysyem.valueobject.CustomerId; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Component +public class CreditHistoryRepositoryImpl implements CreditHistoryRepository { + + private final CreditHistoryJpaRepository creditHistoryJpaRepository; + private final CreditHistoryDataAccessMapper creditHistoryDataAccessMapper; + + public CreditHistoryRepositoryImpl(CreditHistoryJpaRepository creditHistoryJpaRepository, + CreditHistoryDataAccessMapper creditHistoryDataAccessMapper) { + this.creditHistoryJpaRepository = creditHistoryJpaRepository; + this.creditHistoryDataAccessMapper = creditHistoryDataAccessMapper; + } + + @Override + public CreditHistory save(CreditHistory creditHistory) { + return creditHistoryDataAccessMapper.creditHistoryEntityToCreditHistory(creditHistoryJpaRepository + .save(creditHistoryDataAccessMapper.creditHistoryToCreditHistoryEntity(creditHistory))); + } + + @Override + public Optional> findByCustomerId(CustomerId customerId) { + Optional> creditHistory = + creditHistoryJpaRepository.findByCustomerId(customerId.getValue()); + return creditHistory + .map(creditHistoryList -> + creditHistoryList.stream() + .map(creditHistoryDataAccessMapper::creditHistoryEntityToCreditHistory) + .collect(Collectors.toList())); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/entity/CreditHistoryEntity.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/entity/CreditHistoryEntity.java new file mode 100644 index 0000000..fff4bc2 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/entity/CreditHistoryEntity.java @@ -0,0 +1,39 @@ +package com.food.order.system.payment.data.access.credithistory.entity; + +import com.food.order.system.payment.service.domain.valueobject.TransactionType; +import lombok.*; + +import javax.persistence.*; +import java.math.BigDecimal; +import java.util.Objects; +import java.util.UUID; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "credit_history") +@Entity +public class CreditHistoryEntity { + + @Id + private UUID id; + private UUID customerId; + private BigDecimal amount; + @Enumerated(EnumType.STRING) + private TransactionType type; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CreditHistoryEntity that = (CreditHistoryEntity) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/exception/CreditHistoryDataaccessException.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/exception/CreditHistoryDataaccessException.java new file mode 100644 index 0000000..0db46e7 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/exception/CreditHistoryDataaccessException.java @@ -0,0 +1,8 @@ +package com.food.order.system.payment.data.access.credithistory.exception; + +public class CreditHistoryDataaccessException extends RuntimeException { + + public CreditHistoryDataaccessException(String message) { + super(message); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/mapper/CreditHistoryDataAccessMapper.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/mapper/CreditHistoryDataAccessMapper.java new file mode 100644 index 0000000..001218f --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/mapper/CreditHistoryDataAccessMapper.java @@ -0,0 +1,32 @@ +package com.food.order.system.payment.data.access.credithistory.mapper; + + +import com.food.order.system.payment.data.access.credithistory.entity.CreditHistoryEntity; +import com.food.order.system.payment.service.domain.entity.CreditHistory; +import com.food.order.system.payment.service.domain.valueobject.CreditHistoryId; +import com.food.order.sysyem.valueobject.CustomerId; +import com.food.order.sysyem.valueobject.Money; +import org.springframework.stereotype.Component; + +@Component +public class CreditHistoryDataAccessMapper { + + public CreditHistory creditHistoryEntityToCreditHistory(CreditHistoryEntity creditHistoryEntity) { + return CreditHistory.builder() + .id(new CreditHistoryId(creditHistoryEntity.getId())) + .customerId(new CustomerId(creditHistoryEntity.getCustomerId())) + .amount(new Money(creditHistoryEntity.getAmount())) + .transactionType(creditHistoryEntity.getType()) + .build(); + } + + public CreditHistoryEntity creditHistoryToCreditHistoryEntity(CreditHistory creditHistory) { + return CreditHistoryEntity.builder() + .id(creditHistory.getId().getValue()) + .customerId(creditHistory.getCustomerId().getValue()) + .amount(creditHistory.getAmount().getAmount()) + .type(creditHistory.getTransactionType()) + .build(); + } + +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/repository/CreditHistoryJpaRepository.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/repository/CreditHistoryJpaRepository.java new file mode 100644 index 0000000..fb980d6 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/credithistory/repository/CreditHistoryJpaRepository.java @@ -0,0 +1,17 @@ +package com.food.order.system.payment.data.access.credithistory.repository; + +import com.food.order.system.payment.data.access.credithistory.entity.CreditHistoryEntity; +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 CreditHistoryJpaRepository extends JpaRepository { + + Optional> findByCustomerId(UUID customerId); + + +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/adapter/PaymentRepositoryImpl.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/adapter/PaymentRepositoryImpl.java new file mode 100644 index 0000000..7e06623 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/adapter/PaymentRepositoryImpl.java @@ -0,0 +1,37 @@ +package com.food.order.system.payment.data.access.payment.adapter; + + +import com.food.order.system.payment.application.service.ports.output.repository.PaymentRepository; +import com.food.order.system.payment.data.access.payment.mapper.PaymentDataAccessMapper; +import com.food.order.system.payment.data.access.payment.repository.PaymentJpaRepository; +import com.food.order.system.payment.service.domain.entity.Payment; +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.UUID; + +@Component +public class PaymentRepositoryImpl implements PaymentRepository { + + private final PaymentJpaRepository paymentJpaRepository; + private final PaymentDataAccessMapper paymentDataAccessMapper; + + public PaymentRepositoryImpl(PaymentJpaRepository paymentJpaRepository, + PaymentDataAccessMapper paymentDataAccessMapper) { + this.paymentJpaRepository = paymentJpaRepository; + this.paymentDataAccessMapper = paymentDataAccessMapper; + } + + @Override + public Payment save(Payment payment) { + return paymentDataAccessMapper + .paymentEntityToPayment(paymentJpaRepository + .save(paymentDataAccessMapper.paymentToPaymentEntity(payment))); + } + + @Override + public Optional findByOrderId(UUID orderId) { + return paymentJpaRepository.findByOrderId(orderId) + .map(paymentDataAccessMapper::paymentEntityToPayment); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/entity/PaymentEntity.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/entity/PaymentEntity.java new file mode 100644 index 0000000..b733b68 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/entity/PaymentEntity.java @@ -0,0 +1,42 @@ +package com.food.order.system.payment.data.access.payment.entity; + +import com.food.order.sysyem.valueobject.PaymentStatus; +import lombok.*; + +import javax.persistence.*; +import java.math.BigDecimal; +import java.time.ZonedDateTime; +import java.util.Objects; +import java.util.UUID; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "payments") +@Entity +public class PaymentEntity { + + @Id + private UUID id; + private UUID customerId; + private UUID orderId; + private BigDecimal price; + @Enumerated(EnumType.STRING) + private PaymentStatus status; + private ZonedDateTime createdAt; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PaymentEntity that = (PaymentEntity) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/exception/PaymentDataaccessException.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/exception/PaymentDataaccessException.java new file mode 100644 index 0000000..baf23f8 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/exception/PaymentDataaccessException.java @@ -0,0 +1,8 @@ +package com.food.order.system.payment.data.access.payment.exception; + +public class PaymentDataaccessException extends RuntimeException { + + public PaymentDataaccessException(String message) { + super(message); + } +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/mapper/PaymentDataAccessMapper.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/mapper/PaymentDataAccessMapper.java new file mode 100644 index 0000000..b1e7ac7 --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/mapper/PaymentDataAccessMapper.java @@ -0,0 +1,36 @@ +package com.food.order.system.payment.data.access.payment.mapper; + + +import com.food.order.system.payment.data.access.payment.entity.PaymentEntity; +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.system.payment.service.domain.valueobject.PaymentId; +import com.food.order.sysyem.valueobject.CustomerId; +import com.food.order.sysyem.valueobject.Money; +import com.food.order.sysyem.valueobject.OrderId; +import org.springframework.stereotype.Component; + +@Component +public class PaymentDataAccessMapper { + + public PaymentEntity paymentToPaymentEntity(Payment payment) { + return PaymentEntity.builder() + .id(payment.getId().getValue()) + .customerId(payment.getCustomerId().getValue()) + .orderId(payment.getOrderId().getValue()) + .price(payment.getPrice().getAmount()) + .status(payment.getStatus()) + .createdAt(payment.getCreatedAt()) + .build(); + } + + public Payment paymentEntityToPayment(PaymentEntity paymentEntity) { + return Payment.builder() + .id(new PaymentId(paymentEntity.getId())) + .customerId(new CustomerId(paymentEntity.getCustomerId())) + .orderId(new OrderId(paymentEntity.getOrderId())) + .price(new Money(paymentEntity.getPrice())) + .createdAt(paymentEntity.getCreatedAt()) + .build(); + } + +} diff --git a/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/repository/PaymentJpaRepository.java b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/repository/PaymentJpaRepository.java new file mode 100644 index 0000000..d651b9e --- /dev/null +++ b/payment-service/payment-dataaccess/src/main/java/com/food/order/system/payment/data/access/payment/repository/PaymentJpaRepository.java @@ -0,0 +1,16 @@ +package com.food.order.system.payment.data.access.payment.repository; + +import com.food.order.system.payment.data.access.payment.entity.PaymentEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; +import java.util.UUID; + +@Repository +public interface PaymentJpaRepository extends JpaRepository { + + Optional findByOrderId(UUID orderId); + + +} diff --git a/payment-service/payment-domain/payment-application-service/pom.xml b/payment-service/payment-domain/payment-application-service/pom.xml new file mode 100644 index 0000000..ea2f151 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/pom.xml @@ -0,0 +1,45 @@ + + + + payment-domain + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + payment-application-service + + + + + com.food.order + payment-domain + + + + com.food.order + common-domain + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework + spring-tx + + + com.food.order + payment-domain-core + 1.0-SNAPSHOT + compile + + + + + + \ No newline at end of file diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/PaymentRequestHelper.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/PaymentRequestHelper.java new file mode 100644 index 0000000..0ba13d1 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/PaymentRequestHelper.java @@ -0,0 +1,90 @@ +package com.food.order.system.payment.application.service; + +import com.food.order.system.payment.application.service.dto.PaymentRequest; +import com.food.order.system.payment.application.service.exception.PaymentApplicationServiceException; +import com.food.order.system.payment.application.service.mapper.PaymentDataMapper; +import com.food.order.system.payment.application.service.ports.output.repository.CreditEntryRepository; +import com.food.order.system.payment.application.service.ports.output.repository.CreditHistoryRepository; +import com.food.order.system.payment.application.service.ports.output.repository.PaymentRepository; +import com.food.order.system.payment.service.domain.PaymentDomainService; +import com.food.order.system.payment.service.domain.entity.CreditEntry; +import com.food.order.system.payment.service.domain.entity.CreditHistory; +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.system.payment.service.domain.event.PaymentCancelledEvent; +import com.food.order.system.payment.service.domain.event.PaymentCompletedEvent; +import com.food.order.system.payment.service.domain.event.PaymentEvent; +import com.food.order.system.payment.service.domain.event.PaymentFailedEvent; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; +import com.food.order.sysyem.valueobject.CustomerId; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Component +@Slf4j +@RequiredArgsConstructor +public class PaymentRequestHelper { + private final PaymentDomainService paymentDomainService; + private final PaymentDataMapper paymentDataMapper; + private final PaymentRepository paymentRepository; + private final CreditEntryRepository creditEntryRepository; + private final CreditHistoryRepository creditHistoryRepository; + + private final DomainEventPublisher publisher; + private final DomainEventPublisher publisherCancelled; + + private final DomainEventPublisher failedEventDomainEventPublisher; + + @Transactional + public PaymentEvent persistPayment(PaymentRequest paymentRequest) { + log.info("Received payment complete event for id : {}", paymentRequest.getOrderId()); + var payment = paymentDataMapper.paymentRequestModelToPayment(paymentRequest); + var creditEntry = getCreditEntry(payment.getCustomerId()); + var creditHistory = getCreditHistory(payment.getCustomerId()); + List failureMessage = new ArrayList<>(); + + var paymentEvent = paymentDomainService.validateAndInitializePayment + (payment, creditEntry, creditHistory, failureMessage,publisher,failedEventDomainEventPublisher); + + persistDbObject(payment, creditEntry, creditHistory, failureMessage); + return paymentEvent; + } + + + public PaymentEvent persistCancelPayment(PaymentRequest paymentRequest) { + log.info("Received payment cancel event for id : {}", paymentRequest.getOrderId()); + var payment = paymentRepository.findByOrderId + (UUID.fromString(paymentRequest.getOrderId())).orElseThrow( + () -> new PaymentApplicationServiceException("Payment not found")); + var creditEntry = getCreditEntry(payment.getCustomerId()); + var creditHistory = getCreditHistory(payment.getCustomerId()); + List failureMessage = new ArrayList<>(); + var paymentEvent = paymentDomainService.validateAndCancelledPayment + (payment, creditEntry, creditHistory, failureMessage,publisherCancelled,failedEventDomainEventPublisher); + + persistDbObject(payment, creditEntry, creditHistory, failureMessage); + return paymentEvent; + } + + private void persistDbObject(Payment payment, CreditEntry creditEntry, List creditHistory, List failureMessage) { + paymentRepository.save(payment); + if (failureMessage.isEmpty()) { + creditEntryRepository.save(creditEntry); + creditHistoryRepository.save(creditHistory.get(creditHistory.size() - 1)); + } + } + private List getCreditHistory(CustomerId customerId) { + return creditHistoryRepository.findByCustomerId(customerId).orElseThrow( + () -> new PaymentApplicationServiceException("No credit history found for customer id : " + customerId)); + } + + private CreditEntry getCreditEntry(CustomerId customerId) { + return creditEntryRepository.findByCustomerId(customerId).orElseThrow( + () -> new PaymentApplicationServiceException("Credit entry not found for customer id : " + customerId)); + } +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/PaymentRequestMessageListenerImpl.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/PaymentRequestMessageListenerImpl.java new file mode 100644 index 0000000..ce7ad55 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/PaymentRequestMessageListenerImpl.java @@ -0,0 +1,35 @@ +package com.food.order.system.payment.application.service; + +import com.food.order.system.payment.application.service.dto.PaymentRequest; +import com.food.order.system.payment.application.service.ports.input.message.listener.PaymentRequestMessageListener; +import com.food.order.system.payment.service.domain.event.PaymentEvent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +@RequiredArgsConstructor +public class PaymentRequestMessageListenerImpl implements PaymentRequestMessageListener { + + private final PaymentRequestHelper paymentRequestHelper; + + @Override + public void completePayment(PaymentRequest paymentRequest) { + var event = paymentRequestHelper.persistPayment(paymentRequest); + fireEvent(event); + } + @Override + public void cancelPayment(PaymentRequest paymentRequest) { + var event = paymentRequestHelper.persistCancelPayment(paymentRequest); + fireEvent(event); + } + private void fireEvent(PaymentEvent event) { + + log.info("Firing event : {}", event); + event.fire(); + + } + + +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/config/PaymentServiceConfigData.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/config/PaymentServiceConfigData.java new file mode 100644 index 0000000..10b34ec --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/config/PaymentServiceConfigData.java @@ -0,0 +1,15 @@ +package com.food.order.system.payment.application.service.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties(prefix = "payment-service") +public class PaymentServiceConfigData { + + private String paymentRequestTopicName; + private String paymentResponseTopicName; + +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/dto/PaymentRequest.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/dto/PaymentRequest.java new file mode 100644 index 0000000..d98c845 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/dto/PaymentRequest.java @@ -0,0 +1,26 @@ +package com.food.order.system.payment.application.service.dto; + +import com.food.order.sysyem.valueobject.PaymentOrderStatus; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.math.BigDecimal; +import java.time.Instant; + +@Getter +@Builder +@AllArgsConstructor +public class PaymentRequest { + private String id; + private String sagaId; + private String orderId; + private String customerId; + private BigDecimal price; + private Instant createdAt; + private PaymentOrderStatus status; + + public void setStatus(PaymentOrderStatus status) { + this.status = status; + } +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/exception/PaymentApplicationServiceException.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/exception/PaymentApplicationServiceException.java new file mode 100644 index 0000000..8ad2bec --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/exception/PaymentApplicationServiceException.java @@ -0,0 +1,14 @@ +package com.food.order.system.payment.application.service.exception; + +import com.food.order.sysyem.exception.DomainException; + +public class PaymentApplicationServiceException extends DomainException { + + public PaymentApplicationServiceException(String message) { + super(message); + } + + public PaymentApplicationServiceException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/mapper/PaymentDataMapper.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/mapper/PaymentDataMapper.java new file mode 100644 index 0000000..1de2426 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/mapper/PaymentDataMapper.java @@ -0,0 +1,23 @@ +package com.food.order.system.payment.application.service.mapper; + +import com.food.order.system.payment.application.service.dto.PaymentRequest; +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.sysyem.valueobject.CustomerId; +import com.food.order.sysyem.valueobject.Money; +import com.food.order.sysyem.valueobject.OrderId; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +@Component +public class PaymentDataMapper { + + + public Payment paymentRequestModelToPayment(PaymentRequest paymentRequest) { + return Payment.builder() + .customerId(new CustomerId(UUID.fromString(paymentRequest.getCustomerId()))) + .orderId(new OrderId(UUID.fromString(paymentRequest.getOrderId()))) + .price(new Money(paymentRequest.getPrice())) + .build(); + } +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/input/message/listener/PaymentRequestMessageListener.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/input/message/listener/PaymentRequestMessageListener.java new file mode 100644 index 0000000..b8abc9b --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/input/message/listener/PaymentRequestMessageListener.java @@ -0,0 +1,8 @@ +package com.food.order.system.payment.application.service.ports.input.message.listener; + +import com.food.order.system.payment.application.service.dto.PaymentRequest; + +public interface PaymentRequestMessageListener { + void completePayment(PaymentRequest paymentRequest); + void cancelPayment(PaymentRequest paymentRequest); +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentCancelledMessagePublisher.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentCancelledMessagePublisher.java new file mode 100644 index 0000000..6fb5925 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentCancelledMessagePublisher.java @@ -0,0 +1,7 @@ +package com.food.order.system.payment.application.service.ports.output.message.publisher; + +import com.food.order.system.payment.service.domain.event.PaymentCancelledEvent; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; + +public interface PaymentCancelledMessagePublisher extends DomainEventPublisher { +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentCompletedMessagePublisher.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentCompletedMessagePublisher.java new file mode 100644 index 0000000..a50ede5 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentCompletedMessagePublisher.java @@ -0,0 +1,7 @@ +package com.food.order.system.payment.application.service.ports.output.message.publisher; + +import com.food.order.system.payment.service.domain.event.PaymentCompletedEvent; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; + +public interface PaymentCompletedMessagePublisher extends DomainEventPublisher { +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentFailedMessagePublisher.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentFailedMessagePublisher.java new file mode 100644 index 0000000..5cf76ff --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/message/publisher/PaymentFailedMessagePublisher.java @@ -0,0 +1,7 @@ +package com.food.order.system.payment.application.service.ports.output.message.publisher; + +import com.food.order.system.payment.service.domain.event.PaymentFailedEvent; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; + +public interface PaymentFailedMessagePublisher extends DomainEventPublisher { +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/CreditEntryRepository.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/CreditEntryRepository.java new file mode 100644 index 0000000..87d2100 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/CreditEntryRepository.java @@ -0,0 +1,11 @@ +package com.food.order.system.payment.application.service.ports.output.repository; + +import com.food.order.system.payment.service.domain.entity.CreditEntry; +import com.food.order.sysyem.valueobject.CustomerId; + +import java.util.Optional; + +public interface CreditEntryRepository { + CreditEntry save(CreditEntry creditEntry); + Optional findByCustomerId(CustomerId orderId); +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/CreditHistoryRepository.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/CreditHistoryRepository.java new file mode 100644 index 0000000..443ed81 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/CreditHistoryRepository.java @@ -0,0 +1,12 @@ +package com.food.order.system.payment.application.service.ports.output.repository; + +import com.food.order.system.payment.service.domain.entity.CreditHistory; +import com.food.order.sysyem.valueobject.CustomerId; + +import java.util.List; +import java.util.Optional; + +public interface CreditHistoryRepository { + CreditHistory save(CreditHistory creditHistory); + Optional> findByCustomerId(CustomerId orderId); +} diff --git a/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/PaymentRepository.java b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/PaymentRepository.java new file mode 100644 index 0000000..e582155 --- /dev/null +++ b/payment-service/payment-domain/payment-application-service/src/main/java/com/food/order/system/payment/application/service/ports/output/repository/PaymentRepository.java @@ -0,0 +1,13 @@ +package com.food.order.system.payment.application.service.ports.output.repository; + +import com.food.order.system.payment.service.domain.entity.Payment; + +import java.util.Optional; +import java.util.UUID; + +public interface PaymentRepository { + Payment save(Payment payment); + Optional findByOrderId(UUID orderId); + + +} diff --git a/payment-service/payment-domain/payment-domain-core/pom.xml b/payment-service/payment-domain/payment-domain-core/pom.xml new file mode 100644 index 0000000..35ed9b1 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/pom.xml @@ -0,0 +1,22 @@ + + + + payment-domain + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + payment-domain-core + + + + com.food.order + common-domain + + + + + \ No newline at end of file diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/PaymentDomainService.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/PaymentDomainService.java new file mode 100644 index 0000000..1c050a9 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/PaymentDomainService.java @@ -0,0 +1,29 @@ +package com.food.order.system.payment.service.domain; + +import com.food.order.system.payment.service.domain.entity.CreditEntry; +import com.food.order.system.payment.service.domain.entity.CreditHistory; +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.system.payment.service.domain.event.PaymentCancelledEvent; +import com.food.order.system.payment.service.domain.event.PaymentCompletedEvent; +import com.food.order.system.payment.service.domain.event.PaymentEvent; +import com.food.order.system.payment.service.domain.event.PaymentFailedEvent; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; + +import java.util.List; + +public interface PaymentDomainService { + + PaymentEvent validateAndInitializePayment( Payment paymentEvent, + CreditEntry creditEntry, + List creditHistory, + List failureMessages, + DomainEventPublisher publisher, + DomainEventPublisher failedEventDomainEventPublisher); + + PaymentEvent validateAndCancelledPayment( Payment paymentEvent, + CreditEntry creditEntry, + List creditHistory, + List failureMessages, + DomainEventPublisher publisher, + DomainEventPublisher failedEventDomainEventPublisher); +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/PaymentDomainServiceImpl.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/PaymentDomainServiceImpl.java new file mode 100644 index 0000000..570dd55 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/PaymentDomainServiceImpl.java @@ -0,0 +1,127 @@ +package com.food.order.system.payment.service.domain; + +import com.food.order.system.payment.service.domain.entity.CreditEntry; +import com.food.order.system.payment.service.domain.entity.CreditHistory; +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.system.payment.service.domain.event.PaymentCancelledEvent; +import com.food.order.system.payment.service.domain.event.PaymentCompletedEvent; +import com.food.order.system.payment.service.domain.event.PaymentEvent; +import com.food.order.system.payment.service.domain.event.PaymentFailedEvent; +import com.food.order.system.payment.service.domain.valueobject.CreditHistoryId; +import com.food.order.system.payment.service.domain.valueobject.TransactionType; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; +import com.food.order.sysyem.valueobject.Money; +import com.food.order.sysyem.valueobject.PaymentStatus; +import lombok.extern.slf4j.Slf4j; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.UUID; + +import static com.food.order.sysyem.DomainConstants.UTC; + +@Slf4j +public class PaymentDomainServiceImpl implements PaymentDomainService { + + + @Override + public PaymentEvent validateAndInitializePayment(Payment payment, + CreditEntry creditEntry, + List creditHistory, + List failureMessages, + DomainEventPublisher publisher, + DomainEventPublisher failedPublisher) { + payment.validatePayment(failureMessages); + payment.initializePayment(); + validateCreditEntry(payment,creditEntry,failureMessages); + subtractCreditEntry(payment,creditEntry); + updateCreditHistory(payment,creditHistory, TransactionType.DEBIT); + validateCreditHistory(creditEntry,creditHistory,failureMessages); + + if (failureMessages.isEmpty()) { + log.info("Payment is valid and initialized"); + payment.updateStatus(PaymentStatus.COMPLETED); + return new PaymentCompletedEvent(payment, ZonedDateTime.now(ZoneId.of(UTC)),publisher ); + } else { + log.info("Payment is invalid and not initialized"); + payment.updateStatus(PaymentStatus.FAILED); + return new PaymentFailedEvent(payment, ZonedDateTime.now(ZoneId.of(UTC)), failureMessages,failedPublisher); + } + + } + + @Override + public PaymentEvent validateAndCancelledPayment(Payment payment, + CreditEntry creditEntry, + List creditHistory, + List failureMessages, + DomainEventPublisher publisher, + DomainEventPublisher failedPublisher) { + + payment.validatePayment(failureMessages); + addCreditEntry(payment,creditEntry); + updateCreditHistory(payment,creditHistory, TransactionType.CREDIT); + + if (failureMessages.isEmpty()) { + log.info("Payment is valid and cancelled"); + payment.updateStatus(PaymentStatus.CANCELED); + return new PaymentCancelledEvent(payment, ZonedDateTime.now(ZoneId.of(UTC)),publisher); + } else { + log.info("Payment is invalid and not cancelled"); + payment.updateStatus(PaymentStatus.FAILED); + return new PaymentFailedEvent(payment, ZonedDateTime.now(ZoneId.of(UTC)), failureMessages,failedPublisher); + } + } + + private void addCreditEntry(Payment payment, CreditEntry creditEntry) { + creditEntry.addCreditAmount(payment.getPrice()); + } + + private void validateCreditHistory(CreditEntry creditEntry, List creditHistory, List failureMessages) { + var totalCreditHistory = getTotalHistoryAmount(creditHistory, TransactionType.CREDIT); + var totalDebitHistory = getTotalHistoryAmount(creditHistory, TransactionType.DEBIT); + + if (totalDebitHistory.isGreaterThan(totalCreditHistory)) { + failureMessages.add("Customer id " + creditEntry.getCustomerId() + " has insufficient credit"); + log.error("Customer id {} has insufficient credit", creditEntry.getCustomerId()); + } + + if (!creditEntry.getTotalCreditAmount().equals(totalCreditHistory.subtract(totalDebitHistory))) { + failureMessages.add("Customer id " + creditEntry.getCustomerId() + " has total is not equal to credit history"); + log.error("Customer id {} has total is not equal to credit history", creditEntry.getCustomerId()); + } + } + + private Money getTotalHistoryAmount(List creditHistory, TransactionType transactionType) { + return creditHistory.stream() + .filter(history -> transactionType.equals(history.getTransactionType())) + .map(CreditHistory::getAmount) + .reduce(Money.ZERO, Money::add); + } + + private void updateCreditHistory(Payment payment, List creditHistory, TransactionType transactionType) { + creditHistory.add( + CreditHistory.builder() + .id(new CreditHistoryId(UUID.randomUUID())) + .customerId(payment.getCustomerId()) + .amount(payment.getPrice()) + .transactionType(transactionType) + .build() + ); + } + + private void subtractCreditEntry(Payment payment, CreditEntry creditEntry) { + creditEntry.subtractCreditAmount(payment.getPrice()); + } + + private void validateCreditEntry(Payment payment, CreditEntry creditEntry, List failureMessages) { + if(payment.getPrice().isGreaterThan(creditEntry.getTotalCreditAmount())){ + failureMessages.add("Customer id "+ payment.getCustomerId() + " , has insufficient credit amount" + + creditEntry.getTotalCreditAmount() + " to pay for order id " + payment.getOrderId()); + log.error("Payment price is greater than credit"); + } + } + + +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/CreditEntry.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/CreditEntry.java new file mode 100644 index 0000000..2e03161 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/CreditEntry.java @@ -0,0 +1,70 @@ +package com.food.order.system.payment.service.domain.entity; + +import com.food.order.system.payment.service.domain.valueobject.CreditEntryId; +import com.food.order.sysyem.entity.BaseEntity; +import com.food.order.sysyem.valueobject.CustomerId; +import com.food.order.sysyem.valueobject.Money; + +public class CreditEntry extends BaseEntity { + + private final CustomerId customerId; + + private Money totalCreditAmount; + + public void addCreditAmount(Money creditAmount) { + totalCreditAmount = totalCreditAmount.add(creditAmount); + } + + public void subtractCreditAmount(Money creditAmount) { + totalCreditAmount = totalCreditAmount.subtract(creditAmount); + } + + + + private CreditEntry(Builder builder) { + setId(builder.creditEntryId); + customerId = builder.customerId; + totalCreditAmount = builder.totalCreditAmount; + } + + public static Builder builder() { + return new Builder(); + } + + public CustomerId getCustomerId() { + return customerId; + } + + public Money getTotalCreditAmount() { + return totalCreditAmount; + } + + + public static final class Builder { + private CreditEntryId creditEntryId; + private CustomerId customerId; + private Money totalCreditAmount; + + private Builder() { + } + + public Builder id(CreditEntryId val) { + creditEntryId = val; + return this; + } + + public Builder customerId(CustomerId val) { + customerId = val; + return this; + } + + public Builder totalCreditAmount(Money val) { + totalCreditAmount = val; + return this; + } + + public CreditEntry build() { + return new CreditEntry(this); + } + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/CreditHistory.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/CreditHistory.java new file mode 100644 index 0000000..9c1f1d0 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/CreditHistory.java @@ -0,0 +1,72 @@ +package com.food.order.system.payment.service.domain.entity; + +import com.food.order.system.payment.service.domain.valueobject.CreditHistoryId; +import com.food.order.system.payment.service.domain.valueobject.TransactionType; +import com.food.order.sysyem.entity.BaseEntity; +import com.food.order.sysyem.valueobject.CustomerId; +import com.food.order.sysyem.valueobject.Money; + +public class CreditHistory extends BaseEntity { + + private final CustomerId customerId; + private final Money amount; + private final TransactionType transactionType; + + private CreditHistory(Builder builder) { + setId(builder.creditHistoryId); + customerId = builder.customerId; + amount = builder.amount; + transactionType = builder.transactionType; + } + + public static Builder builder() { + return new Builder(); + } + + + public CustomerId getCustomerId() { + return customerId; + } + + public Money getAmount() { + return amount; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public static final class Builder { + private CreditHistoryId creditHistoryId; + private CustomerId customerId; + private Money amount; + private TransactionType transactionType; + + private Builder() { + } + + public Builder id(CreditHistoryId val) { + creditHistoryId = val; + return this; + } + + public Builder customerId(CustomerId val) { + customerId = val; + return this; + } + + public Builder amount(Money val) { + amount = val; + return this; + } + + public Builder transactionType(TransactionType val) { + transactionType = val; + return this; + } + + public CreditHistory build() { + return new CreditHistory(this); + } + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/Payment.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/Payment.java new file mode 100644 index 0000000..7577f02 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/entity/Payment.java @@ -0,0 +1,119 @@ +package com.food.order.system.payment.service.domain.entity; + +import com.food.order.system.payment.service.domain.valueobject.PaymentId; +import com.food.order.sysyem.entity.AggregateRoot; +import com.food.order.sysyem.valueobject.CustomerId; +import com.food.order.sysyem.valueobject.Money; +import com.food.order.sysyem.valueobject.OrderId; +import com.food.order.sysyem.valueobject.PaymentStatus; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +public class Payment extends AggregateRoot { + + private final OrderId orderId; + private final CustomerId customerId; + private final Money price; + + private PaymentStatus status; + private ZonedDateTime createdAt; + + public void initializePayment(){ + setId(new PaymentId(UUID.randomUUID())); + createdAt = ZonedDateTime.now(ZoneId.of("UTC")); + } + + public void validatePayment(List failureMessages){ + if (Objects.isNull(price) || !price.isGreaterThanZero()){ + failureMessages.add("Payment price must be greater than zero"); + } + } + + public void updateStatus ( PaymentStatus status ) { + this.status = status; + } + + private Payment(Builder builder) { + setId(builder.paymentId); + orderId = builder.orderId; + customerId = builder.customerId; + price = builder.price; + status = builder.status; + createdAt = builder.createdAt; + } + + public static Builder builder() { + return new Builder(); + } + + + public OrderId getOrderId() { + return orderId; + } + + public CustomerId getCustomerId() { + return customerId; + } + + public Money getPrice() { + return price; + } + + public PaymentStatus getStatus() { + return status; + } + + public ZonedDateTime getCreatedAt() { + return createdAt; + } + + public static final class Builder { + private PaymentId paymentId; + private OrderId orderId; + private CustomerId customerId; + private Money price; + private PaymentStatus status; + private ZonedDateTime createdAt; + + private Builder() { + } + + public Builder id(PaymentId val) { + paymentId = val; + return this; + } + + public Builder orderId(OrderId val) { + orderId = val; + return this; + } + + public Builder customerId(CustomerId val) { + customerId = val; + return this; + } + + public Builder price(Money val) { + price = val; + return this; + } + + public Builder status(PaymentStatus val) { + status = val; + return this; + } + + public Builder createdAt(ZonedDateTime val) { + createdAt = val; + return this; + } + + public Payment build() { + return new Payment(this); + } + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentCancelledEvent.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentCancelledEvent.java new file mode 100644 index 0000000..835d5fa --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentCancelledEvent.java @@ -0,0 +1,23 @@ +package com.food.order.system.payment.service.domain.event; + +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; + +import java.time.ZonedDateTime; +import java.util.Collections; + +public class PaymentCancelledEvent extends PaymentEvent{ + + private final DomainEventPublisher publisher; + + public PaymentCancelledEvent(Payment payment, ZonedDateTime createdAt, DomainEventPublisher publisher) { + super(payment, createdAt, Collections.emptyList()); + this.publisher = publisher; + } + + + @Override + public void fire() { + publisher.publish(this); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentCompletedEvent.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentCompletedEvent.java new file mode 100644 index 0000000..399b34d --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentCompletedEvent.java @@ -0,0 +1,25 @@ +package com.food.order.system.payment.service.domain.event; + +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; + +import java.time.ZonedDateTime; +import java.util.Collections; + +public class PaymentCompletedEvent extends PaymentEvent{ + + private final DomainEventPublisher publisher; + + public PaymentCompletedEvent(Payment payment, + ZonedDateTime createdAt, + DomainEventPublisher publisher) { + super(payment, createdAt , Collections.emptyList()); + this.publisher = publisher; + } + + + @Override + public void fire() { + publisher.publish(this); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentEvent.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentEvent.java new file mode 100644 index 0000000..ce361d2 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentEvent.java @@ -0,0 +1,31 @@ +package com.food.order.system.payment.service.domain.event; + +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.sysyem.event.DomainEvent; + +import java.time.ZonedDateTime; +import java.util.List; + +public abstract class PaymentEvent implements DomainEvent { + private final Payment payment; + private final ZonedDateTime createdAt; + private final List failureMessages; + + public PaymentEvent(Payment payment, ZonedDateTime createdAt, List failureMessages) { + this.payment = payment; + this.createdAt = createdAt; + this.failureMessages = failureMessages; + } + + public Payment getPayment() { + return payment; + } + + public ZonedDateTime getCreatedAt() { + return createdAt; + } + + public List getFailureMessages() { + return failureMessages; + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentFailedEvent.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentFailedEvent.java new file mode 100644 index 0000000..6838c43 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/event/PaymentFailedEvent.java @@ -0,0 +1,23 @@ +package com.food.order.system.payment.service.domain.event; + +import com.food.order.system.payment.service.domain.entity.Payment; +import com.food.order.sysyem.event.publisher.DomainEventPublisher; + +import java.time.ZonedDateTime; +import java.util.List; + +public class PaymentFailedEvent extends PaymentEvent{ + + private final DomainEventPublisher publisher; + + public PaymentFailedEvent(Payment payment, ZonedDateTime createdAt, List failureMessages, + DomainEventPublisher publisher) { + super(payment, createdAt, failureMessages); + this.publisher = publisher; + } + + @Override + public void fire() { + publisher.publish(this); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/exception/PayemntDomainException.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/exception/PayemntDomainException.java new file mode 100644 index 0000000..eaa11ba --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/exception/PayemntDomainException.java @@ -0,0 +1,13 @@ +package com.food.order.system.payment.service.domain.exception; + +import com.food.order.sysyem.exception.DomainException; + +public class PayemntDomainException extends DomainException { + public PayemntDomainException(String message) { + super(message); + } + + public PayemntDomainException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/exception/PaymentNotFoundException.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/exception/PaymentNotFoundException.java new file mode 100644 index 0000000..8f52ba1 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/exception/PaymentNotFoundException.java @@ -0,0 +1,13 @@ +package com.food.order.system.payment.service.domain.exception; + +import com.food.order.sysyem.exception.DomainException; + +public class PaymentNotFoundException extends DomainException { + public PaymentNotFoundException(String message) { + super(message); + } + + public PaymentNotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/CreditEntryId.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/CreditEntryId.java new file mode 100644 index 0000000..043d8ac --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/CreditEntryId.java @@ -0,0 +1,11 @@ +package com.food.order.system.payment.service.domain.valueobject; + +import com.food.order.sysyem.valueobject.BaseId; + +import java.util.UUID; + +public class CreditEntryId extends BaseId { + public CreditEntryId(UUID value) { + super(value); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/CreditHistoryId.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/CreditHistoryId.java new file mode 100644 index 0000000..b37a105 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/CreditHistoryId.java @@ -0,0 +1,12 @@ +package com.food.order.system.payment.service.domain.valueobject; + +import com.food.order.sysyem.valueobject.BaseId; + +import java.util.UUID; + +public class CreditHistoryId extends BaseId { + + public CreditHistoryId(UUID value) { + super(value); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/PaymentId.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/PaymentId.java new file mode 100644 index 0000000..3dc8d61 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/PaymentId.java @@ -0,0 +1,11 @@ +package com.food.order.system.payment.service.domain.valueobject; + +import com.food.order.sysyem.valueobject.BaseId; + +import java.util.UUID; + +public class PaymentId extends BaseId { + public PaymentId(UUID id) { + super(id); + } +} diff --git a/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/TransactionType.java b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/TransactionType.java new file mode 100644 index 0000000..09b8a79 --- /dev/null +++ b/payment-service/payment-domain/payment-domain-core/src/main/java/com/food/order/system/payment/service/domain/valueobject/TransactionType.java @@ -0,0 +1,5 @@ +package com.food.order.system.payment.service.domain.valueobject; + +public enum TransactionType { + DEBIT, CREDIT +} diff --git a/payment-service/payment-domain/pom.xml b/payment-service/payment-domain/pom.xml new file mode 100644 index 0000000..4f05e65 --- /dev/null +++ b/payment-service/payment-domain/pom.xml @@ -0,0 +1,20 @@ + + + + payment-service + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + payment-domain + pom + + payment-domain-core + payment-application-service + + + + \ No newline at end of file diff --git a/payment-service/payment-messaging/pom.xml b/payment-service/payment-messaging/pom.xml new file mode 100644 index 0000000..7d03db9 --- /dev/null +++ b/payment-service/payment-messaging/pom.xml @@ -0,0 +1,15 @@ + + + + payment-service + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + payment-messaging + + + \ No newline at end of file diff --git a/payment-service/pom.xml b/payment-service/pom.xml new file mode 100644 index 0000000..3bae58c --- /dev/null +++ b/payment-service/pom.xml @@ -0,0 +1,22 @@ + + + + food-ordering-system + com.food.order + 1.0-SNAPSHOT + + 4.0.0 + + payment-service + pom + + payment-domain + payment-dataaccess + payment-messaging + payment-container + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 5c05d3e..b3f2b38 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ spring-boot-starter-parent org.springframework.boot - 2.7.1 + 2.6.7 4.0.0 @@ -15,6 +15,7 @@ infrastructure infrastructure/kafka customer-service + payment-service @@ -41,12 +42,24 @@ ${project.version} + + com.food.order + payment-domain + ${project.version} + + com.food.order order-app ${project.version} + + com.food.order + payment-application-service + ${project.version} + + com.food.order order-application-service