diff --git a/common/src/main/java/com/nashtech/common/command/ApproveOrderCommand.java b/common/src/main/java/com/nashtech/common/command/ApproveOrderCommand.java index 02a1de45..5b9d4188 100644 --- a/common/src/main/java/com/nashtech/common/command/ApproveOrderCommand.java +++ b/common/src/main/java/com/nashtech/common/command/ApproveOrderCommand.java @@ -10,6 +10,8 @@ public class ApproveOrderCommand { @TargetAggregateIdentifier String orderId; + String paymentId; + String shipmentId; OrderStatus orderStatus; } \ No newline at end of file diff --git a/common/src/main/java/com/nashtech/common/command/CancelShipmentCommand.java b/common/src/main/java/com/nashtech/common/command/CancelShipmentCommand.java index 0f6b95ba..a8420aae 100644 --- a/common/src/main/java/com/nashtech/common/command/CancelShipmentCommand.java +++ b/common/src/main/java/com/nashtech/common/command/CancelShipmentCommand.java @@ -14,7 +14,13 @@ public class CancelShipmentCommand { String productId; Integer quantity; Double price; + Double subTotal; + Double grandTotal; + Float tax; String userId; + String firstName; + String lastName; + String address; String reasonToFailed; String paymentId; ShipmentStatus shipmentStatus = ShipmentStatus.SHIPMENT_CANCELLED; diff --git a/common/src/main/java/com/nashtech/common/command/CreateShipmentCommand.java b/common/src/main/java/com/nashtech/common/command/CreateShipmentCommand.java new file mode 100644 index 00000000..fa0f8d69 --- /dev/null +++ b/common/src/main/java/com/nashtech/common/command/CreateShipmentCommand.java @@ -0,0 +1,23 @@ +package com.nashtech.common.command; + +import com.nashtech.common.model.User; +import lombok.Builder; +import lombok.Value; +import org.axonframework.modelling.command.TargetAggregateIdentifier; + +@Value +@Builder +public class CreateShipmentCommand { + @TargetAggregateIdentifier + String shipmentId; + String paymentId; + String orderId; + User user; + String productId; + Double subTotal; + Double total; + Float tax; + Double basePrice; + Integer quantity; + +} diff --git a/common/src/main/java/com/nashtech/common/command/CreatedShipmentCommand.java b/common/src/main/java/com/nashtech/common/command/CreatedShipmentCommand.java index ab293e58..8a35e4c3 100644 --- a/common/src/main/java/com/nashtech/common/command/CreatedShipmentCommand.java +++ b/common/src/main/java/com/nashtech/common/command/CreatedShipmentCommand.java @@ -14,7 +14,13 @@ public class CreatedShipmentCommand { String productId; Integer quantity; Double price; + Double subTotal; + Double grandTotal; + Float tax; String userId; + String firstName; + String lastName; + String address; String paymentId; ShipmentStatus shipmentStatus = ShipmentStatus.SHIPMENT_CREATED; } diff --git a/common/src/main/java/com/nashtech/common/command/ProcessPaymentCommand.java b/common/src/main/java/com/nashtech/common/command/ProcessPaymentCommand.java index 32e08c7e..faceaec2 100644 --- a/common/src/main/java/com/nashtech/common/command/ProcessPaymentCommand.java +++ b/common/src/main/java/com/nashtech/common/command/ProcessPaymentCommand.java @@ -1,8 +1,5 @@ package com.nashtech.common.command; -import com.nashtech.common.model.PaymentDetails; -import com.nashtech.common.model.PaymentStatus; -import com.nashtech.common.model.User; import lombok.Builder; import lombok.Value; import org.axonframework.modelling.command.TargetAggregateIdentifier; @@ -13,12 +10,10 @@ public class ProcessPaymentCommand { @TargetAggregateIdentifier String paymentId; String orderId; - Double price; Integer quantity; + Float tax; + Double baseAmount; String productId; - User userDetails; - PaymentDetails paymentDetails; - PaymentStatus paymentStatus = PaymentStatus.PAYMENT_APPROVED; - + String userId; } \ No newline at end of file diff --git a/common/src/main/java/com/nashtech/common/command/ReserveProductCommand.java b/common/src/main/java/com/nashtech/common/command/ReserveProductCommand.java index a79e0365..4beb4985 100644 --- a/common/src/main/java/com/nashtech/common/command/ReserveProductCommand.java +++ b/common/src/main/java/com/nashtech/common/command/ReserveProductCommand.java @@ -9,10 +9,10 @@ public class ReserveProductCommand { @TargetAggregateIdentifier String productId; + String orderId; + String userId; String title; Double basePrice; Integer quantity; Float tax; - String orderId; - String userId; } diff --git a/common/src/main/java/com/nashtech/common/event/OrderShippedEvent.java b/common/src/main/java/com/nashtech/common/event/OrderShippedEvent.java index 8fcad472..c0cbacee 100644 --- a/common/src/main/java/com/nashtech/common/event/OrderShippedEvent.java +++ b/common/src/main/java/com/nashtech/common/event/OrderShippedEvent.java @@ -7,5 +7,6 @@ @Builder public class OrderShippedEvent { String orderId; - + String paymentId; + String shipmentId; } diff --git a/common/src/main/java/com/nashtech/common/event/PaymentApprovedEvent.java b/common/src/main/java/com/nashtech/common/event/PaymentApprovedEvent.java index 5122d3f7..8ae8e722 100644 --- a/common/src/main/java/com/nashtech/common/event/PaymentApprovedEvent.java +++ b/common/src/main/java/com/nashtech/common/event/PaymentApprovedEvent.java @@ -1,6 +1,6 @@ package com.nashtech.common.event; -import com.nashtech.common.model.PaymentStatus; +import com.nashtech.common.model.User; import lombok.Builder; import lombok.Value; @@ -9,11 +9,12 @@ public class PaymentApprovedEvent { String paymentId; String orderId; - Double price; - String userId; - Integer quantity; String productId; - PaymentStatus paymentStatus; - + User user; + Integer quantity; + Double subTotal; + Double total; + Float tax; + Double basePrice; } \ No newline at end of file diff --git a/common/src/main/java/com/nashtech/common/event/PaymentCancelledEvent.java b/common/src/main/java/com/nashtech/common/event/PaymentCancelledEvent.java index fef33e6e..690f97a6 100644 --- a/common/src/main/java/com/nashtech/common/event/PaymentCancelledEvent.java +++ b/common/src/main/java/com/nashtech/common/event/PaymentCancelledEvent.java @@ -11,7 +11,7 @@ public class PaymentCancelledEvent { String orderId; Integer quantity; String userId; - String reason; + String reasonToFailed; String productId; PaymentStatus paymentStatus; diff --git a/common/src/main/java/com/nashtech/common/event/ProductFailedEvent.java b/common/src/main/java/com/nashtech/common/event/ProductFailedEvent.java new file mode 100644 index 00000000..044da46f --- /dev/null +++ b/common/src/main/java/com/nashtech/common/event/ProductFailedEvent.java @@ -0,0 +1,14 @@ +package com.nashtech.common.event; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class ProductFailedEvent { + String orderId; + String productId; + Integer quantity; + String reasonToFailed; + +} diff --git a/common/src/main/java/com/nashtech/common/event/ProductReserveCancelledEvent.java b/common/src/main/java/com/nashtech/common/event/ProductReserveCancelledEvent.java index 1fa2d887..c4191384 100644 --- a/common/src/main/java/com/nashtech/common/event/ProductReserveCancelledEvent.java +++ b/common/src/main/java/com/nashtech/common/event/ProductReserveCancelledEvent.java @@ -6,7 +6,10 @@ @Value @Builder public class ProductReserveCancelledEvent { + String productId; String orderId; - String reasonToFailed; + String userId; Integer quantity; + String reasonToFailed; + } diff --git a/common/src/main/java/com/nashtech/common/event/ProductReserveFailedEvent.java b/common/src/main/java/com/nashtech/common/event/ProductReserveFailedEvent.java new file mode 100644 index 00000000..a91a3ec8 --- /dev/null +++ b/common/src/main/java/com/nashtech/common/event/ProductReserveFailedEvent.java @@ -0,0 +1,13 @@ +package com.nashtech.common.event; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class ProductReserveFailedEvent { + String orderId; + String userId; + String productId; + String reasonToFailed; +} diff --git a/common/src/main/java/com/nashtech/common/event/ProductReservedEvent.java b/common/src/main/java/com/nashtech/common/event/ProductReservedEvent.java index cc81a54e..0039dcc8 100644 --- a/common/src/main/java/com/nashtech/common/event/ProductReservedEvent.java +++ b/common/src/main/java/com/nashtech/common/event/ProductReservedEvent.java @@ -6,10 +6,12 @@ @Value @Builder public class ProductReservedEvent { - String productId; - Double price; - Integer quantity; String orderId; String userId; + String productId; + String title; + Double baseAmount; + Float tax; + Integer quantity; } \ No newline at end of file diff --git a/common/src/main/java/com/nashtech/common/event/ShipmentCancelledEvent.java b/common/src/main/java/com/nashtech/common/event/ShipmentCancelledEvent.java index e53b155a..b4ec278b 100644 --- a/common/src/main/java/com/nashtech/common/event/ShipmentCancelledEvent.java +++ b/common/src/main/java/com/nashtech/common/event/ShipmentCancelledEvent.java @@ -12,7 +12,13 @@ public class ShipmentCancelledEvent { String productId; Integer quantity; Double price; + Double subTotal; + Double grandTotal; + Float tax; String userId; + String firstName; + String lastName; + String address; String reasonToFailed; String paymentId; ShipmentStatus shipmentStatus; diff --git a/common/src/main/java/com/nashtech/common/event/ShipmentCreatedEvent.java b/common/src/main/java/com/nashtech/common/event/ShipmentCreatedEvent.java index e8365a6f..83b646bd 100644 --- a/common/src/main/java/com/nashtech/common/event/ShipmentCreatedEvent.java +++ b/common/src/main/java/com/nashtech/common/event/ShipmentCreatedEvent.java @@ -1,6 +1,6 @@ package com.nashtech.common.event; -import com.nashtech.common.model.ShipmentStatus; +import com.nashtech.common.model.User; import lombok.Builder; import lombok.Value; @@ -8,11 +8,14 @@ @Builder public class ShipmentCreatedEvent { String shipmentId; + String paymentId; String orderId; + User user; String productId; + Double subTotal; + Double total; + Float tax; + Double basePrice; Integer quantity; - Double price; - String userId; - String paymentId; - ShipmentStatus shipmentStatus; + } diff --git a/common/src/main/java/com/nashtech/common/model/PaymentDetails.java b/common/src/main/java/com/nashtech/common/model/PaymentDetails.java index 915387e2..c7e7a266 100644 --- a/common/src/main/java/com/nashtech/common/model/PaymentDetails.java +++ b/common/src/main/java/com/nashtech/common/model/PaymentDetails.java @@ -6,10 +6,12 @@ @Value @Builder public class PaymentDetails { + String userId; String bank; String cardNumber; Integer validUntilMonth; Integer validUntilYear; Integer cvv; + Double balanceAmount; } \ No newline at end of file diff --git a/common/src/main/java/com/nashtech/common/model/User.java b/common/src/main/java/com/nashtech/common/model/User.java index 4c365d73..776622fd 100644 --- a/common/src/main/java/com/nashtech/common/model/User.java +++ b/common/src/main/java/com/nashtech/common/model/User.java @@ -1,14 +1,16 @@ package com.nashtech.common.model; import lombok.Builder; -import lombok.Value; +import lombok.Data; -@Value +@Data @Builder public class User { - String firstName; - String lastName; - String userId; - String address; + private String userId; + private String firstName; + private String lastName; + private String address; + private String emailId; + private String mobileNumber; } \ No newline at end of file diff --git a/common/src/main/java/com/nashtech/common/utils/OrderStatus.java b/common/src/main/java/com/nashtech/common/utils/OrderStatus.java index 35eeb584..5dd01e64 100644 --- a/common/src/main/java/com/nashtech/common/utils/OrderStatus.java +++ b/common/src/main/java/com/nashtech/common/utils/OrderStatus.java @@ -1,6 +1,6 @@ package com.nashtech.common.utils; public enum OrderStatus { - ORDER_CREATED, ORDER_APPROVED, ORDER_REJECTED + ORDER_NOT_APPROVED,ORDER_PARTIALLY_APPROVED, ORDER_APPROVED, ORDER_PLACED } \ No newline at end of file diff --git a/inventory-service/app-config.yaml b/inventory-service/app-config.yaml new file mode 100644 index 00000000..63d30df1 --- /dev/null +++ b/inventory-service/app-config.yaml @@ -0,0 +1,8 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: inventory-configmap +data: + # Configuration values can be set as key-value properties + MYSQL_HOST: 35.231.178.113 + AXON_HOST: 34.23.126.183:8124 diff --git a/inventory-service/deployment.yaml b/inventory-service/deployment.yaml index 4a139921..1961f955 100644 --- a/inventory-service/deployment.yaml +++ b/inventory-service/deployment.yaml @@ -22,3 +22,19 @@ spec: - name: http containerPort: 9091 protocol: TCP + env: + - name: MYSQL_DB_USERNAME + valueFrom: + secretKeyRef: + name: secret-to-be-created + key: mysql-db-username + optional: false + - name: MYSQL_DB_PASSWORD + valueFrom: + secretKeyRef: + name: secret-to-be-created + key: mysql-db-userpassword + optional: false + envFrom: + - configMapRef: + name: inventory-configmap \ No newline at end of file diff --git a/inventory-service/kustomization.yaml b/inventory-service/kustomization.yaml index 42a42ff1..4809c39a 100644 --- a/inventory-service/kustomization.yaml +++ b/inventory-service/kustomization.yaml @@ -2,6 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: +- secretstore.yaml +- app-config.yaml - service.yaml - deployment.yaml diff --git a/inventory-service/pom.xml b/inventory-service/pom.xml index 1668344a..8a34fb0c 100644 --- a/inventory-service/pom.xml +++ b/inventory-service/pom.xml @@ -11,8 +11,7 @@ com.nashtech.inventory inventory-service 1.0.0 - Inventory-Mircoservice - Demo project for Spring Boot + inventory-service @@ -87,11 +86,6 @@ org.springframework spring-web - - - - - javax.validation diff --git a/inventory-service/secretstore.yaml b/inventory-service/secretstore.yaml new file mode 100644 index 00000000..2d9f8e99 --- /dev/null +++ b/inventory-service/secretstore.yaml @@ -0,0 +1,42 @@ +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: car-demo-inventory-secretstore + namespace: default +spec: + provider: + gcpsm: + auth: + secretRef: + secretAccessKeySecretRef: + name: gcpsm-secret + key: secret-access-credentials + projectID: boreal-gravity-396810 +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: car-demo-externalsecret + namespace: default +spec: + secretStoreRef: + name: car-demo-inventory-secretstore + kind: SecretStore + target: + name: secret-to-be-created + data: + - secretKey: "mysql-db-username" + remoteRef: + key: car-demo-secret + version: latest + property: mysql-db-username + - secretKey: "mysql-db-userpassword" + remoteRef: + key: car-demo-secret + version: latest + property: mysql-db-userpassword + + - secretKey: "MY_SQL_SECRETS" + remoteRef: + key: car-demo-secret + version: latest \ No newline at end of file diff --git a/inventory-service/src/main/java/com/nashtech/inventory/InventoryServiceApplication.java b/inventory-service/src/main/java/com/nashtech/inventory/InventoryServiceApplication.java index 66556f78..01418e57 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/InventoryServiceApplication.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/InventoryServiceApplication.java @@ -1,7 +1,7 @@ package com.nashtech.inventory; import com.nashtech.inventory.command.interceptors.CreateProductCommandInterceptor; -import com.nashtech.inventory.core.errorhandling.ProductsServiceEventsErrorHandler; +import com.nashtech.inventory.exception.ProductsServiceEventsErrorHandler; import org.axonframework.commandhandling.CommandBus; import org.axonframework.config.EventProcessingConfigurer; import org.springframework.beans.factory.annotation.Autowired; diff --git a/inventory-service/src/main/java/com/nashtech/inventory/command/InventoryAggregate.java b/inventory-service/src/main/java/com/nashtech/inventory/aggregate/InventoryAggregate.java similarity index 62% rename from inventory-service/src/main/java/com/nashtech/inventory/command/InventoryAggregate.java rename to inventory-service/src/main/java/com/nashtech/inventory/aggregate/InventoryAggregate.java index da9d48bf..86667245 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/command/InventoryAggregate.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/aggregate/InventoryAggregate.java @@ -1,10 +1,14 @@ -package com.nashtech.inventory.command; +package com.nashtech.inventory.aggregate; +import com.nashtech.common.command.CancelProductReserveCommand; import com.nashtech.common.command.ReserveProductCommand; import com.nashtech.common.event.ProductReserveCancelledEvent; +import com.nashtech.common.event.ProductReserveFailedEvent; import com.nashtech.common.event.ProductReservedEvent; -import com.nashtech.inventory.core.events.ProductCreatedEvent; +import com.nashtech.inventory.command.CreateProductCommand; +import com.nashtech.inventory.events.ProductCreatedEvent; +import lombok.extern.slf4j.Slf4j; import org.axonframework.commandhandling.CommandHandler; import org.axonframework.eventsourcing.EventSourcingHandler; import org.axonframework.modelling.command.AggregateIdentifier; @@ -15,28 +19,32 @@ @Aggregate +@Slf4j public class InventoryAggregate{ @AggregateIdentifier private String productId; private String title; - private Double price; + private Double basePrice; + private Float tax; private Integer quantity; + private String userId; + private String orderId; + public InventoryAggregate() { } @CommandHandler public InventoryAggregate(CreateProductCommand createProductCommand) { - + log.info("CreateProductCommand started with productId {}",createProductCommand.getProductId()); if(createProductCommand.getTitle() == null || createProductCommand.getTitle().isBlank()) { throw new IllegalArgumentException("Title cannot be empty"); } ProductCreatedEvent productCreatedEvent = new ProductCreatedEvent(); - BeanUtils.copyProperties(createProductCommand, productCreatedEvent); AggregateLifecycle.apply(productCreatedEvent); @@ -44,18 +52,25 @@ public InventoryAggregate(CreateProductCommand createProductCommand) { @CommandHandler public void handle(ReserveProductCommand reserveProductCommand) { - + log.info("ReserveProductCommand started with productId {}",reserveProductCommand.getProductId()); if(quantity < reserveProductCommand.getQuantity()) { - ProductReserveCancelledEvent productReserveCancelledEvent = ProductReserveCancelledEvent.builder() + ProductReserveFailedEvent productFailedEvent = ProductReserveFailedEvent.builder() + .productId(reserveProductCommand.getProductId()) + .userId(reserveProductCommand.getUserId()) .orderId(reserveProductCommand.getOrderId()) .reasonToFailed("Insufficient number of items in stock").build(); + AggregateLifecycle.apply(productFailedEvent); + return; } ProductReservedEvent productReservedEvent = ProductReservedEvent.builder() .orderId(reserveProductCommand.getOrderId()) .productId(reserveProductCommand.getProductId()) - .quantity(reserveProductCommand.getQuantity()) .userId(reserveProductCommand.getUserId()) + .quantity(reserveProductCommand.getQuantity()) + .title(title) + .baseAmount(basePrice) + .tax(tax) .build(); AggregateLifecycle.apply(productReservedEvent); @@ -63,11 +78,13 @@ public void handle(ReserveProductCommand reserveProductCommand) { } @CommandHandler - public void handle(ProductReserveCancelledEvent cancelProductReservationCommand) { - - ProductReserveCancelledEvent productReservationCancelledEvent = - ProductReserveCancelledEvent.builder() + public void handle(CancelProductReserveCommand cancelProductReservationCommand) { + log.info("ProductReserveCancelledEvent started with productId {}",cancelProductReservationCommand.getProductId()); + ProductReserveCancelledEvent productReservationCancelledEvent = ProductReserveCancelledEvent.builder() + .productId(cancelProductReservationCommand.getProductId()) + .userId(cancelProductReservationCommand.getUserId()) .orderId(cancelProductReservationCommand.getOrderId()) + .quantity(cancelProductReservationCommand.getQuantity()) .build(); AggregateLifecycle.apply(productReservationCancelledEvent); @@ -84,7 +101,8 @@ public void on(ProductReserveCancelledEvent productReservationCancelledEvent) { @EventSourcingHandler public void on(ProductCreatedEvent productCreatedEvent) { this.productId = productCreatedEvent.getProductId(); - this.price = productCreatedEvent.getPrice(); + this.basePrice = productCreatedEvent.getBasePrice(); + this.tax = productCreatedEvent.getTax(); this.title = productCreatedEvent.getTitle(); this.quantity = productCreatedEvent.getQuantity(); } @@ -92,9 +110,9 @@ public void on(ProductCreatedEvent productCreatedEvent) { @EventSourcingHandler public void on(ProductReservedEvent productReservedEvent) { + this.userId = productReservedEvent.getUserId(); + this.orderId = productReservedEvent.getOrderId(); this.quantity -= productReservedEvent.getQuantity(); } - - } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/command/CreateProductCommand.java b/inventory-service/src/main/java/com/nashtech/inventory/command/CreateProductCommand.java index da3f8fa2..e3e3f77f 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/command/CreateProductCommand.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/command/CreateProductCommand.java @@ -1,18 +1,17 @@ package com.nashtech.inventory.command; +import lombok.Builder; import lombok.Value; import org.axonframework.modelling.command.TargetAggregateIdentifier; -import lombok.Builder; - @Builder @Value public class CreateProductCommand { - @TargetAggregateIdentifier String productId; String title; - Double price; + Double basePrice; + Float tax; Integer quantity; } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/command/interceptors/CreateProductCommandInterceptor.java b/inventory-service/src/main/java/com/nashtech/inventory/command/interceptors/CreateProductCommandInterceptor.java index 81d96f14..1d557d3e 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/command/interceptors/CreateProductCommandInterceptor.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/command/interceptors/CreateProductCommandInterceptor.java @@ -1,24 +1,20 @@ package com.nashtech.inventory.command.interceptors; -import java.math.BigDecimal; -import java.util.List; -import java.util.function.BiFunction; - - import com.nashtech.inventory.command.CreateProductCommand; -import com.nashtech.inventory.core.data.ProductLookupEntity; -import com.nashtech.inventory.core.data.ProductLookupRepository; +import com.nashtech.inventory.repository.ProductLookupEntity; +import com.nashtech.inventory.repository.ProductLookupRepository; +import lombok.extern.slf4j.Slf4j; import org.axonframework.commandhandling.CommandMessage; import org.axonframework.messaging.MessageDispatchInterceptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.function.BiFunction; + @Component +@Slf4j public class CreateProductCommandInterceptor implements MessageDispatchInterceptor> { - - private static final Logger LOGGER = LoggerFactory.getLogger(CreateProductCommandInterceptor.class); private final ProductLookupRepository productLookupRepository; public CreateProductCommandInterceptor(ProductLookupRepository productLookupRepository) { @@ -31,14 +27,13 @@ public BiFunction, CommandMessage> handle( return (index, command) -> { - LOGGER.info("Intercepted command: " + command.getPayloadType()); + log.info("Intercepted command: " + command.getPayloadType()); if(CreateProductCommand.class.equals(command.getPayloadType())) { CreateProductCommand createProductCommand = (CreateProductCommand)command.getPayload(); - ProductLookupEntity productLookupEntity = productLookupRepository.findByProductIdOrTitle(createProductCommand.getProductId(), - createProductCommand.getTitle()); + ProductLookupEntity productLookupEntity = productLookupRepository.findByProductId(createProductCommand.getProductId()); if(productLookupEntity != null) { throw new IllegalStateException( diff --git a/inventory-service/src/main/java/com/nashtech/inventory/command/rest/ProductsController.java b/inventory-service/src/main/java/com/nashtech/inventory/command/rest/ProductsController.java deleted file mode 100644 index 596960a5..00000000 --- a/inventory-service/src/main/java/com/nashtech/inventory/command/rest/ProductsController.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.nashtech.inventory.command.rest; - -import com.nashtech.inventory.command.CreateProductCommand; -import com.nashtech.inventory.query.FindProductsQuery; -import com.nashtech.inventory.query.rest.ProductRestModel; -import org.axonframework.commandhandling.gateway.CommandGateway; -import org.axonframework.messaging.responsetypes.ResponseTypes; -import org.axonframework.queryhandling.QueryGateway; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; - -import javax.validation.Valid; -import java.util.List; -import java.util.UUID; - -@RestController -@RequestMapping("/products") -public class ProductsController { - @Autowired - private QueryGateway queryGateway; - private final CommandGateway commandGateway; - - public ProductsController(CommandGateway commandGateway) { - this.commandGateway = commandGateway; - } - @GetMapping("get") - public List getProducts() { - FindProductsQuery findProductsQuery = new FindProductsQuery(); - return queryGateway.query(findProductsQuery, - ResponseTypes.multipleInstancesOf(ProductRestModel.class)).join(); - } - - - @PostMapping - public String createProduct(@Valid @RequestBody CreateProductRestModel createProductRestModel) { - - CreateProductCommand createProductCommand = CreateProductCommand.builder() - .price(createProductRestModel.getPrice()) - .quantity(createProductRestModel.getQuantity()) - .title(createProductRestModel.getTitle()) - .productId(UUID.randomUUID().toString()).build(); - - String returnValue; - - returnValue = commandGateway.sendAndWait(createProductCommand); - - - return returnValue; - } -} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/config/AxonXStreamConfig.java b/inventory-service/src/main/java/com/nashtech/inventory/config/AxonXStreamConfig.java new file mode 100644 index 00000000..a94d2923 --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/config/AxonXStreamConfig.java @@ -0,0 +1,19 @@ +package com.nashtech.inventory.config; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.security.AnyTypePermission; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AxonXStreamConfig { + + @Bean + public XStream xStream() { + XStream xStream = new XStream(); + xStream.addPermission(AnyTypePermission.ANY); + + return xStream; + } + +} \ No newline at end of file diff --git a/inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductLookupEntity.java b/inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductLookupEntity.java deleted file mode 100644 index 461ab22f..00000000 --- a/inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductLookupEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.nashtech.inventory.core.data; - -import java.io.Serializable; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - - - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Entity -@Table(name="productlookup") -public class ProductLookupEntity implements Serializable { - - private static final long serialVersionUID = 2788007460547645663L; - - @Id - private String productId; - - @Column(unique=true) - private String title; - -} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/core/events/ProductCreatedEvent.java b/inventory-service/src/main/java/com/nashtech/inventory/events/ProductCreatedEvent.java similarity index 59% rename from inventory-service/src/main/java/com/nashtech/inventory/core/events/ProductCreatedEvent.java rename to inventory-service/src/main/java/com/nashtech/inventory/events/ProductCreatedEvent.java index 74456c36..35f6caad 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/core/events/ProductCreatedEvent.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/events/ProductCreatedEvent.java @@ -1,6 +1,4 @@ -package com.nashtech.inventory.core.events; - -import java.math.BigDecimal; +package com.nashtech.inventory.events; import lombok.Data; @@ -9,7 +7,8 @@ public class ProductCreatedEvent { private String productId; private String title; - private Double price; + private Double basePrice; + private Float tax; private Integer quantity; } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/core/errorhandling/ErrorMessage.java b/inventory-service/src/main/java/com/nashtech/inventory/exception/ErrorMessage.java similarity index 79% rename from inventory-service/src/main/java/com/nashtech/inventory/core/errorhandling/ErrorMessage.java rename to inventory-service/src/main/java/com/nashtech/inventory/exception/ErrorMessage.java index 8bbf0597..073441af 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/core/errorhandling/ErrorMessage.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/exception/ErrorMessage.java @@ -1,10 +1,10 @@ -package com.nashtech.inventory.core.errorhandling; - -import java.util.Date; +package com.nashtech.inventory.exception; import lombok.AllArgsConstructor; import lombok.Data; +import java.util.Date; + @Data @AllArgsConstructor public class ErrorMessage { diff --git a/inventory-service/src/main/java/com/nashtech/inventory/core/errorhandling/ProductsServiceEventsErrorHandler.java b/inventory-service/src/main/java/com/nashtech/inventory/exception/ProductsServiceEventsErrorHandler.java similarity index 89% rename from inventory-service/src/main/java/com/nashtech/inventory/core/errorhandling/ProductsServiceEventsErrorHandler.java rename to inventory-service/src/main/java/com/nashtech/inventory/exception/ProductsServiceEventsErrorHandler.java index 63bbdb68..1cfb371c 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/core/errorhandling/ProductsServiceEventsErrorHandler.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/exception/ProductsServiceEventsErrorHandler.java @@ -1,4 +1,4 @@ -package com.nashtech.inventory.core.errorhandling; +package com.nashtech.inventory.exception; import org.axonframework.eventhandling.EventMessage; import org.axonframework.eventhandling.EventMessageHandler; diff --git a/inventory-service/src/main/java/com/nashtech/inventory/handler/ProductEventsHandler.java b/inventory-service/src/main/java/com/nashtech/inventory/handler/ProductEventsHandler.java new file mode 100644 index 00000000..6290a201 --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/handler/ProductEventsHandler.java @@ -0,0 +1,79 @@ +package com.nashtech.inventory.handler; + + +import com.nashtech.common.event.ProductReserveCancelledEvent; +import com.nashtech.common.event.ProductReservedEvent; +import com.nashtech.inventory.events.ProductCreatedEvent; +import com.nashtech.inventory.repository.Product; +import com.nashtech.inventory.repository.ProductsRepository; +import com.nashtech.inventory.repository.ProductsSold; +import com.nashtech.inventory.repository.ProductsSoldRepository; +import lombok.extern.slf4j.Slf4j; +import org.axonframework.config.ProcessingGroup; +import org.axonframework.eventhandling.EventHandler; +import org.axonframework.messaging.interceptors.ExceptionHandler; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Component; + + +@Component +@ProcessingGroup("product-group") +@Slf4j +public class ProductEventsHandler { + + private final ProductsRepository productsRepository; + private final ProductsSoldRepository productsSoldRepository; + + public ProductEventsHandler(ProductsRepository productsRepository, ProductsSoldRepository productsSoldRepository) { + this.productsRepository = productsRepository; + this.productsSoldRepository = productsSoldRepository; + } + + @EventHandler + public void on(ProductCreatedEvent event) { + Product productEntity = new Product(); + BeanUtils.copyProperties(event, productEntity); + productsRepository.save(productEntity); + } + + @EventHandler + public void on(ProductReservedEvent productReservedEvent) { + log.info("ProductReservedEvent: Remaining product stock {}", productReservedEvent.getQuantity()); + Product product = productsRepository.findByProductId(productReservedEvent.getProductId()); + product.setQuantity(product.getQuantity() - productReservedEvent.getQuantity()); + productsRepository.save(product); + + ProductsSold soldProduct = new ProductsSold(product.getProductId(), productReservedEvent.getOrderId(), + productReservedEvent.getUserId(), productReservedEvent.getQuantity(),productReservedEvent.getTitle(), + productReservedEvent.getBaseAmount(),productReservedEvent.getTax()); + productsSoldRepository.save(soldProduct); + } + + @EventHandler + public void on(ProductReserveCancelledEvent productReservationCancelledEvent) { + log.info("ProductReservationCancelledEvent: Reversing product {} quantity {}", + productReservationCancelledEvent.getQuantity(), productReservationCancelledEvent.getProductId()); + + Product currentlyStoredProduct = productsRepository.findByProductId(productReservationCancelledEvent.getOrderId()); + currentlyStoredProduct.setQuantity(currentlyStoredProduct.getQuantity() + + productReservationCancelledEvent.getQuantity()); + + productsRepository.save(currentlyStoredProduct); + + log.info("Stable product {} quantity {}", productReservationCancelledEvent.getProductId(), + currentlyStoredProduct.getQuantity()); + + ProductsSold currentlyStoredSoldProduct = + productsSoldRepository.findByProductIdAndOrderId(productReservationCancelledEvent.getProductId(), + productReservationCancelledEvent.getOrderId()); + if (currentlyStoredSoldProduct != null) { + productsSoldRepository.delete(currentlyStoredSoldProduct); + } + } + + @ExceptionHandler(resultType = Exception.class) + public void handle(Exception exception) throws Exception { + throw exception; + } + +} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/command/ProductLookupEventsHandler.java b/inventory-service/src/main/java/com/nashtech/inventory/handler/ProductLookupEventsHandler.java similarity index 53% rename from inventory-service/src/main/java/com/nashtech/inventory/command/ProductLookupEventsHandler.java rename to inventory-service/src/main/java/com/nashtech/inventory/handler/ProductLookupEventsHandler.java index c36a7eb7..1a4c31d9 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/command/ProductLookupEventsHandler.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/handler/ProductLookupEventsHandler.java @@ -1,11 +1,10 @@ -package com.nashtech.inventory.command; +package com.nashtech.inventory.handler; -import com.nashtech.inventory.core.data.ProductLookupEntity; -import com.nashtech.inventory.core.data.ProductLookupRepository; -import com.nashtech.inventory.core.events.ProductCreatedEvent; +import com.nashtech.inventory.events.ProductCreatedEvent; +import com.nashtech.inventory.repository.ProductLookupEntity; +import com.nashtech.inventory.repository.ProductLookupRepository; import org.axonframework.config.ProcessingGroup; import org.axonframework.eventhandling.EventHandler; -import org.axonframework.eventhandling.ResetHandler; import org.springframework.stereotype.Component; @@ -21,12 +20,7 @@ public ProductLookupEventsHandler(ProductLookupRepository productLookupRepositor @EventHandler public void on(ProductCreatedEvent event) { - - ProductLookupEntity productLookupEntity = new ProductLookupEntity(event.getProductId(), - event.getTitle()); - - productLookupRepository.save(productLookupEntity); - + productLookupRepository.save(new ProductLookupEntity(event.getProductId())); } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/query/ProductEventsHandler.java b/inventory-service/src/main/java/com/nashtech/inventory/query/ProductEventsHandler.java deleted file mode 100644 index 02e22dc5..00000000 --- a/inventory-service/src/main/java/com/nashtech/inventory/query/ProductEventsHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.nashtech.inventory.query; - - -import com.nashtech.common.event.ProductReserveCancelledEvent; -import com.nashtech.common.event.ProductReservedEvent; -import com.nashtech.inventory.core.data.Product; -import com.nashtech.inventory.core.data.ProductsRepository; -import com.nashtech.inventory.core.events.ProductCreatedEvent; -import org.axonframework.config.ProcessingGroup; -import org.axonframework.eventhandling.EventHandler; -import org.axonframework.eventhandling.ResetHandler; -import org.axonframework.messaging.interceptors.ExceptionHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.stereotype.Component; - - -@Component -@ProcessingGroup("product-group") -public class ProductEventsHandler { - - private final ProductsRepository productsRepository; - private static final Logger LOGGER = LoggerFactory.getLogger(ProductEventsHandler.class); - - public ProductEventsHandler(ProductsRepository productsRepository) { - this.productsRepository = productsRepository; - } - - @ExceptionHandler(resultType=Exception.class) - public void handle(Exception exception) throws Exception { - throw exception; - } - - @ExceptionHandler(resultType=IllegalArgumentException.class) - public void handle(IllegalArgumentException exception) { - - } - - - @EventHandler - public void on(ProductCreatedEvent event) { - - Product productEntity = new Product(); - BeanUtils.copyProperties(event, productEntity); - - try { - productsRepository.save(productEntity); - } catch (IllegalArgumentException ex) { - ex.printStackTrace(); - } - - } - - @EventHandler - public void on(ProductReservedEvent productReservedEvent) { - Product productEntity = productsRepository.findByProductId(productReservedEvent.getProductId()); - - LOGGER.debug("ProductReservedEvent: Current product quantity " + productEntity.getQuantity()); - - productEntity.setQuantity(productEntity.getQuantity() - productReservedEvent.getQuantity()); - - - productsRepository.save(productEntity); - - LOGGER.debug("ProductReservedEvent: New product quantity " + productEntity.getQuantity()); - - LOGGER.info("ProductReservedEvent is called for productId:" + productReservedEvent.getProductId() + - " and orderId: " + productReservedEvent.getOrderId()); - } - - @EventHandler - public void on(ProductReserveCancelledEvent productReservationCancelledEvent) { - Product currentlyStoredProduct = productsRepository.findByProductId(productReservationCancelledEvent.getOrderId()); - - LOGGER.debug("ProductReservationCancelledEvent: Current product quantity " - + currentlyStoredProduct.getQuantity() ); - - int newQuantity = currentlyStoredProduct.getQuantity() + productReservationCancelledEvent.getQuantity(); - currentlyStoredProduct.setQuantity(newQuantity); - - productsRepository.save(currentlyStoredProduct); - - LOGGER.debug("ProductReservationCancelledEvent: New product quantity " - + currentlyStoredProduct.getQuantity() ); - - } - - @ResetHandler - public void reset() { - productsRepository.deleteAll(); - } - -} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/query/ProductsQueryHandler.java b/inventory-service/src/main/java/com/nashtech/inventory/query/ProductsQueryHandler.java index f86de9fd..ab30b1d8 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/query/ProductsQueryHandler.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/query/ProductsQueryHandler.java @@ -1,15 +1,14 @@ package com.nashtech.inventory.query; -import java.util.ArrayList; -import java.util.List; - -import com.nashtech.inventory.core.data.Product; -import com.nashtech.inventory.core.data.ProductsRepository; -import com.nashtech.inventory.query.rest.ProductRestModel; +import com.nashtech.inventory.repository.Product; +import com.nashtech.inventory.repository.ProductsRepository; import org.axonframework.queryhandling.QueryHandler; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.List; + @Component public class ProductsQueryHandler { @@ -21,18 +20,13 @@ public ProductsQueryHandler(ProductsRepository productsRepository) { } @QueryHandler - public List findProducts(FindProductsQuery query) { - - List productsRest = new ArrayList<>(); - - List storedProducts = productsRepository.findAll(); - - for(Product productEntity: storedProducts) { - ProductRestModel productRestModel = new ProductRestModel(); - BeanUtils.copyProperties(productEntity, productRestModel); - productsRest.add(productRestModel); + public List findProducts(FindProductsQuery query) { + List productsRest = new ArrayList<>(); + for(Product productEntity: productsRepository.findAll()) { + ProductsSummary productRequest = new ProductsSummary(); + BeanUtils.copyProperties(productEntity, productRequest); + productsRest.add(productRequest); } - return productsRest; } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/query/ProductsSummary.java b/inventory-service/src/main/java/com/nashtech/inventory/query/ProductsSummary.java new file mode 100644 index 00000000..7f4b4e07 --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/query/ProductsSummary.java @@ -0,0 +1,13 @@ +package com.nashtech.inventory.query; + +import lombok.Data; + +@Data +public class ProductsSummary { + private String productId; + private String title; + private Double basePrice; + private Float tax; + private Integer quantity; + +} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/query/rest/ProductRestModel.java b/inventory-service/src/main/java/com/nashtech/inventory/query/rest/ProductRestModel.java deleted file mode 100644 index 55e81799..00000000 --- a/inventory-service/src/main/java/com/nashtech/inventory/query/rest/ProductRestModel.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.nashtech.inventory.query.rest; - -import java.math.BigDecimal; - -import lombok.Data; - -@Data -public class ProductRestModel { - private String productId; - private String title; - private Double price; - private Integer quantity; -} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/query/rest/ProductsQueryController.java b/inventory-service/src/main/java/com/nashtech/inventory/query/rest/ProductsQueryController.java deleted file mode 100644 index c2f0e504..00000000 --- a/inventory-service/src/main/java/com/nashtech/inventory/query/rest/ProductsQueryController.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.nashtech.inventory.query.rest; - -import java.util.List; - -import com.nashtech.inventory.query.FindProductsQuery; -import org.axonframework.messaging.responsetypes.ResponseTypes; -import org.axonframework.queryhandling.QueryGateway; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - - - -@RestController -@RequestMapping("/products") -public class ProductsQueryController { - - @Autowired - QueryGateway queryGateway; - - @GetMapping - public List getProducts() { - - FindProductsQuery findProductsQuery = new FindProductsQuery(); - List products = queryGateway.query(findProductsQuery, - ResponseTypes.multipleInstancesOf(ProductRestModel.class)).join(); - - return products; - - - } - -} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/core/data/Product.java b/inventory-service/src/main/java/com/nashtech/inventory/repository/Product.java similarity index 88% rename from inventory-service/src/main/java/com/nashtech/inventory/core/data/Product.java rename to inventory-service/src/main/java/com/nashtech/inventory/repository/Product.java index ab348fb8..29e28dce 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/core/data/Product.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/repository/Product.java @@ -1,4 +1,4 @@ -package com.nashtech.inventory.core.data; +package com.nashtech.inventory.repository; import jakarta.persistence.Entity; import jakarta.persistence.Id; @@ -11,7 +11,6 @@ @Table(name="products") @Data public class Product { - @Id private String productId; private String title; diff --git a/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductLookupEntity.java b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductLookupEntity.java new file mode 100644 index 00000000..0c50495b --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductLookupEntity.java @@ -0,0 +1,18 @@ +package com.nashtech.inventory.repository; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + + +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(name="product_lookup") +public class ProductLookupEntity{ + @Id + private String productId; + +} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductLookupRepository.java b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductLookupRepository.java similarity index 57% rename from inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductLookupRepository.java rename to inventory-service/src/main/java/com/nashtech/inventory/repository/ProductLookupRepository.java index d52f5972..e8ae377f 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductLookupRepository.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductLookupRepository.java @@ -1,7 +1,8 @@ -package com.nashtech.inventory.core.data; +package com.nashtech.inventory.repository; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductLookupRepository extends JpaRepository { - ProductLookupEntity findByProductIdOrTitle(String productId, String title); + ProductLookupEntity findByProductId(String productId); + } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductsRepository.java b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsRepository.java similarity index 63% rename from inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductsRepository.java rename to inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsRepository.java index 7caf51ed..c23460cd 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/core/data/ProductsRepository.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsRepository.java @@ -1,10 +1,8 @@ -package com.nashtech.inventory.core.data; +package com.nashtech.inventory.repository; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductsRepository extends JpaRepository { - Product findByProductId(String productId); - Product findByProductIdOrTitle(String productId, String title); } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsSold.java b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsSold.java new file mode 100644 index 00000000..e16288be --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsSold.java @@ -0,0 +1,24 @@ +package com.nashtech.inventory.repository; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + + +@Entity +@Table(name="products_sold") +@AllArgsConstructor +@NoArgsConstructor +public class ProductsSold { + @Id + private String productId; + private String orderId; + private String userId; + private Integer quantity; + private String title; + private Double baseAmount; + private Float tax; + +} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsSoldRepository.java b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsSoldRepository.java new file mode 100644 index 00000000..f28e4f03 --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/repository/ProductsSoldRepository.java @@ -0,0 +1,8 @@ +package com.nashtech.inventory.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ProductsSoldRepository extends JpaRepository { + ProductsSold findByProductIdAndOrderId(String productId,String orderId); + +} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/command/rest/CreateProductRestModel.java b/inventory-service/src/main/java/com/nashtech/inventory/restapi/ProductRequest.java similarity index 75% rename from inventory-service/src/main/java/com/nashtech/inventory/command/rest/CreateProductRestModel.java rename to inventory-service/src/main/java/com/nashtech/inventory/restapi/ProductRequest.java index 88bb40d8..6964cd96 100644 --- a/inventory-service/src/main/java/com/nashtech/inventory/command/rest/CreateProductRestModel.java +++ b/inventory-service/src/main/java/com/nashtech/inventory/restapi/ProductRequest.java @@ -1,24 +1,17 @@ -package com.nashtech.inventory.command.rest; - -import java.math.BigDecimal; - +package com.nashtech.inventory.restapi; import lombok.Data; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; - @Data -public class CreateProductRestModel { - +public class ProductRequest { @NotBlank(message="Product title is a required field") private String title; - - @Min(value=1, message="Price cannot be lower than 1") - private Double price; - @Min(value=1, message="Quantity cannot be lower than 1") + private Double price; + @Min(value=1, message="Price cannot be lower than 1") private Integer quantity; - + private Float tax; } diff --git a/inventory-service/src/main/java/com/nashtech/inventory/restapi/ProductsController.java b/inventory-service/src/main/java/com/nashtech/inventory/restapi/ProductsController.java new file mode 100644 index 00000000..6a92925b --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/restapi/ProductsController.java @@ -0,0 +1,46 @@ +package com.nashtech.inventory.restapi; + +import com.nashtech.inventory.command.CreateProductCommand; +import com.nashtech.inventory.query.FindProductsQuery; +import com.nashtech.inventory.query.ProductsSummary; +import org.axonframework.commandhandling.gateway.CommandGateway; +import org.axonframework.messaging.responsetypes.ResponseTypes; +import org.axonframework.queryhandling.QueryGateway; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/products") +public class ProductsController { + @Autowired + private QueryGateway queryGateway; + private final CommandGateway commandGateway; + + public ProductsController(CommandGateway commandGateway) { + this.commandGateway = commandGateway; + } + @GetMapping("get") + public List getProducts() { + return queryGateway.query(new FindProductsQuery(), ResponseTypes.multipleInstancesOf(ProductsSummary.class)).join(); + } + + + @PostMapping + public String createProduct(@Valid @RequestBody List createProductRequest) { + createProductRequest.forEach(product->{ + CreateProductCommand createProductCommand = CreateProductCommand.builder() + .basePrice(product.getPrice()) + .quantity(product.getQuantity()) + .title(product.getTitle()) + .tax(product.getTax()) + .productId(UUID.randomUUID().toString()).build(); + commandGateway.send(createProductCommand); + }); + + return "Products added"; + } +} diff --git a/inventory-service/src/main/java/com/nashtech/inventory/restapi/exception/ErrorMessage.java b/inventory-service/src/main/java/com/nashtech/inventory/restapi/exception/ErrorMessage.java new file mode 100644 index 00000000..913b30f0 --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/restapi/exception/ErrorMessage.java @@ -0,0 +1,14 @@ +package com.nashtech.inventory.restapi.exception; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Date; + +@Data +@AllArgsConstructor +public class ErrorMessage { + private final Date timestamp; + private final String message; + +} \ No newline at end of file diff --git a/inventory-service/src/main/java/com/nashtech/inventory/restapi/exception/OrderServiceErrorHandler.java b/inventory-service/src/main/java/com/nashtech/inventory/restapi/exception/OrderServiceErrorHandler.java new file mode 100644 index 00000000..c4775d7c --- /dev/null +++ b/inventory-service/src/main/java/com/nashtech/inventory/restapi/exception/OrderServiceErrorHandler.java @@ -0,0 +1,21 @@ +package com.nashtech.inventory.restapi.exception; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.WebRequest; + +import java.util.Date; + +@ControllerAdvice +public class OrderServiceErrorHandler { + + @ExceptionHandler(value = {Exception.class}) + public ResponseEntity handleOtherExceptions(Exception ex, WebRequest request) { + ErrorMessage errorMessage = new ErrorMessage(new Date(), ex.getMessage()); + return new ResponseEntity<>(errorMessage, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR); + } + +} \ No newline at end of file diff --git a/inventory-service/src/main/resources/application.yml b/inventory-service/src/main/resources/application.yml index d37a68f2..d32c64b5 100644 --- a/inventory-service/src/main/resources/application.yml +++ b/inventory-service/src/main/resources/application.yml @@ -4,10 +4,10 @@ spring: application: name: InventoryService datasource: - url: jdbc:mysql://localhost:3306/inventory_db + url: jdbc:mysql://${MYSQL_HOST:localhost}:3306/inventory_db driverClassName: com.mysql.cj.jdbc.Driver - username: ${DB_USER} - password: ${DB_PASSWORD} + username: ${MYSQL_DB_USERNAME:root} + password: ${MYSQL_DB_PASSWORD:password} jpa: database-platform: org.hibernate.dialect.MySQL8Dialect hibernate: @@ -20,8 +20,4 @@ axon: mode: subscribing axonserver: client-id: InventoryService - servers: ${AXON_HOST} - serializer: - general: default - events: jackson - messages: jackson + servers: ${AXON_HOST:localhost:8124} diff --git a/order-service/app-config.yaml b/order-service/app-config.yaml index 91ad5d62..8e6242c0 100644 --- a/order-service/app-config.yaml +++ b/order-service/app-config.yaml @@ -4,5 +4,5 @@ metadata: name: orderservice-configmap data: # Configuration values can be set as key-value properties - MYSQL_HOST: 34.139.110.70 - AXON_HOST: 35.231.126.212:8124 + MYSQL_HOST: 35.231.178.113 + AXON_HOST: 34.23.126.183:8124 diff --git a/order-service/pom.xml b/order-service/pom.xml index 43a225e5..d0210093 100644 --- a/order-service/pom.xml +++ b/order-service/pom.xml @@ -12,7 +12,6 @@ order-service 1.0.0 order-service - order-service project for Spring Boot diff --git a/order-service/secretstore.yaml b/order-service/secretstore.yaml index 8a9124d9..554613fc 100644 --- a/order-service/secretstore.yaml +++ b/order-service/secretstore.yaml @@ -1,7 +1,7 @@ apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: - name: car-demo-secretstore + name: car-demo-order-secretstore namespace: default spec: provider: @@ -20,7 +20,7 @@ metadata: namespace: default spec: secretStoreRef: - name: car-demo-secretstore + name: car-demo-order-secretstore kind: SecretStore target: name: secret-to-be-created diff --git a/order-service/src/main/java/com/nashtech/order/OrderServiceApplication.java b/order-service/src/main/java/com.nashtech.order/OrderServiceApplication.java similarity index 100% rename from order-service/src/main/java/com/nashtech/order/OrderServiceApplication.java rename to order-service/src/main/java/com.nashtech.order/OrderServiceApplication.java diff --git a/order-service/src/main/java/com/nashtech/order/commands/aggregate/OrderAggregate.java b/order-service/src/main/java/com.nashtech.order/aggregate/OrderAggregate.java similarity index 73% rename from order-service/src/main/java/com/nashtech/order/commands/aggregate/OrderAggregate.java rename to order-service/src/main/java/com.nashtech.order/aggregate/OrderAggregate.java index 461d57a6..77fa59f7 100644 --- a/order-service/src/main/java/com/nashtech/order/commands/aggregate/OrderAggregate.java +++ b/order-service/src/main/java/com.nashtech.order/aggregate/OrderAggregate.java @@ -1,4 +1,4 @@ -package com.nashtech.order.commands.aggregate; +package com.nashtech.order.aggregate; import com.nashtech.common.utils.OrderStatus; import com.nashtech.order.commands.ApproveOrderCommand; @@ -20,11 +20,11 @@ public class OrderAggregate { @AggregateIdentifier private String orderId; - private String carId; + private String productId; private String userId; - private Integer quantity; + private String paymentId; + private String shipmentId; private OrderStatus orderStatus; - private Double price; private String reasonToRejectedOrder; @@ -35,11 +35,10 @@ public OrderAggregate() { public OrderAggregate(CreateOrderCommand createOrderCommand) { OrderCreatedEvent orderCreatedEvent = OrderCreatedEvent.builder() .orderId(createOrderCommand.getOrderId()) - .carId(createOrderCommand.getCarId()) - .price(createOrderCommand.getPrice()) + .productId(createOrderCommand.getProductId()) .quantity(createOrderCommand.getQuantity()) .userId(createOrderCommand.getUserId()) - .orderStatus(OrderStatus.ORDER_CREATED) + .orderStatus(OrderStatus.ORDER_PARTIALLY_APPROVED) .build(); AggregateLifecycle.apply(orderCreatedEvent); } @@ -47,10 +46,8 @@ public OrderAggregate(CreateOrderCommand createOrderCommand) { @EventSourcingHandler public void on(OrderCreatedEvent orderCreatedEvent) { this.orderId = orderCreatedEvent.getOrderId(); - this.carId = orderCreatedEvent.getCarId(); + this.productId = orderCreatedEvent.getProductId(); this.userId = orderCreatedEvent.getUserId(); - this.quantity = orderCreatedEvent.getQuantity(); - this.price = orderCreatedEvent.getPrice(); this.orderStatus = orderCreatedEvent.getOrderStatus(); } @@ -58,6 +55,8 @@ public void on(OrderCreatedEvent orderCreatedEvent) { public void handle(ApproveOrderCommand approveOrderCommand) { OrderApprovedEvent orderApprovedEvent = OrderApprovedEvent.builder() .orderId(approveOrderCommand.getOrderId()) + .paymentId(approveOrderCommand.getPaymentId()) + .shipmentId(approveOrderCommand.getShipmentId()) .orderStatus(approveOrderCommand.getOrderStatus()) .build(); AggregateLifecycle.apply(orderApprovedEvent); @@ -65,6 +64,8 @@ public void handle(ApproveOrderCommand approveOrderCommand) { @EventSourcingHandler public void on(OrderApprovedEvent event) { + this.paymentId = event.getPaymentId(); + this.shipmentId = event.getShipmentId(); this.orderStatus = event.getOrderStatus(); } @@ -72,16 +73,21 @@ public void on(OrderApprovedEvent event) { public void handle(RejectOrderCommand rejectOrderCommand) { OrderCancelledEvent orderCancelledEvent = OrderCancelledEvent.builder() .orderId(rejectOrderCommand.getOrderId()) + .paymentId(rejectOrderCommand.getPaymentId()) + .shipmentId(rejectOrderCommand.getShipmentId()) + .reasonToFailed(rejectOrderCommand.getReasonToFailed()) .orderStatus(rejectOrderCommand.getOrderStatus()) - .reason(rejectOrderCommand.getReasonToReject()) .build(); AggregateLifecycle.apply(orderCancelledEvent); } @EventSourcingHandler public void on(OrderCancelledEvent event) { + this.productId = event.getProductId(); + this.paymentId = event.getPaymentId(); + this.shipmentId = event.getShipmentId(); + this.reasonToRejectedOrder = event.getReasonToFailed(); this.orderStatus = event.getOrderStatus(); - this.reasonToRejectedOrder = event.getReason(); } } diff --git a/order-service/src/main/java/com/nashtech/order/commands/ApproveOrderCommand.java b/order-service/src/main/java/com.nashtech.order/commands/ApproveOrderCommand.java similarity index 87% rename from order-service/src/main/java/com/nashtech/order/commands/ApproveOrderCommand.java rename to order-service/src/main/java/com.nashtech.order/commands/ApproveOrderCommand.java index 215fbb05..8fa0fc45 100644 --- a/order-service/src/main/java/com/nashtech/order/commands/ApproveOrderCommand.java +++ b/order-service/src/main/java/com.nashtech.order/commands/ApproveOrderCommand.java @@ -10,6 +10,7 @@ public class ApproveOrderCommand { @TargetAggregateIdentifier String orderId; + String paymentId; + String shipmentId; OrderStatus orderStatus; - -} \ No newline at end of file +} diff --git a/order-service/src/main/java/com/nashtech/order/commands/CreateOrderCommand.java b/order-service/src/main/java/com.nashtech.order/commands/CreateOrderCommand.java similarity index 89% rename from order-service/src/main/java/com/nashtech/order/commands/CreateOrderCommand.java rename to order-service/src/main/java/com.nashtech.order/commands/CreateOrderCommand.java index 2b759e80..2b3e4adf 100644 --- a/order-service/src/main/java/com/nashtech/order/commands/CreateOrderCommand.java +++ b/order-service/src/main/java/com.nashtech.order/commands/CreateOrderCommand.java @@ -9,8 +9,7 @@ public class CreateOrderCommand { @TargetAggregateIdentifier String orderId; - String carId; - Double price; + String productId; Integer quantity; String userId; diff --git a/order-service/src/main/java/com/nashtech/order/commands/CreateOrderCommandInterceptor.java b/order-service/src/main/java/com.nashtech.order/commands/CreateOrderCommandInterceptor.java similarity index 97% rename from order-service/src/main/java/com/nashtech/order/commands/CreateOrderCommandInterceptor.java rename to order-service/src/main/java/com.nashtech.order/commands/CreateOrderCommandInterceptor.java index 8e448cb0..33a0ad58 100644 --- a/order-service/src/main/java/com/nashtech/order/commands/CreateOrderCommandInterceptor.java +++ b/order-service/src/main/java/com.nashtech.order/commands/CreateOrderCommandInterceptor.java @@ -34,7 +34,7 @@ public BiFunction, CommandMessage> handle(List orderOptional = failedOrderRepository.findById((event.getOrderId())); + if(orderOptional.isEmpty()) { + log.error("Order failed status did not persist {}",event.getOrderId()); + return; + } + FailedOrder order = orderOptional.get(); + order.setProductId(event.getProductId()); + order.setPaymentId(event.getPaymentId()); + order.setShipmentId(event.getShipmentId()); + order.setOrderStatus(event.getOrderStatus().toString()); + order.setReasonToFailed(event.getReasonToFailed()); + failedOrderRepository.save(order); + } + + @ExceptionHandler + public void handle(Exception exception) throws Exception { + log.error("{} occurred during order saving", exception.getMessage()); + throw exception; + } + +} diff --git a/order-service/src/main/java/com/nashtech/order/events/handler/OrderLookupEventsHandler.java b/order-service/src/main/java/com.nashtech.order/handler/OrderLookupEventsHandler.java similarity index 96% rename from order-service/src/main/java/com/nashtech/order/events/handler/OrderLookupEventsHandler.java rename to order-service/src/main/java/com.nashtech.order/handler/OrderLookupEventsHandler.java index cde612cb..02793a99 100644 --- a/order-service/src/main/java/com/nashtech/order/events/handler/OrderLookupEventsHandler.java +++ b/order-service/src/main/java/com.nashtech.order/handler/OrderLookupEventsHandler.java @@ -1,4 +1,4 @@ -package com.nashtech.order.events.handler; +package com.nashtech.order.handler; import com.nashtech.order.events.OrderCreatedEvent; import com.nashtech.order.repository.OrderLookupRepository; diff --git a/order-service/src/main/java/com/nashtech/order/query/FindOrderQuery.java b/order-service/src/main/java/com.nashtech.order/query/FindOrderQuery.java similarity index 100% rename from order-service/src/main/java/com/nashtech/order/query/FindOrderQuery.java rename to order-service/src/main/java/com.nashtech.order/query/FindOrderQuery.java diff --git a/order-service/src/main/java/com/nashtech/order/query/OrderQueriesHandler.java b/order-service/src/main/java/com.nashtech.order/query/OrderQueriesHandler.java similarity index 67% rename from order-service/src/main/java/com/nashtech/order/query/OrderQueriesHandler.java rename to order-service/src/main/java/com.nashtech.order/query/OrderQueriesHandler.java index 68a7ac76..5536f2b8 100644 --- a/order-service/src/main/java/com/nashtech/order/query/OrderQueriesHandler.java +++ b/order-service/src/main/java/com.nashtech.order/query/OrderQueriesHandler.java @@ -1,8 +1,8 @@ package com.nashtech.order.query; -import com.nashtech.order.api.response.OrderSummary; +import com.nashtech.common.utils.OrderStatus; import com.nashtech.order.repository.OrderRepository; -import com.nashtech.order.repository.entity.Order; +import com.nashtech.order.restapi.response.OrderSummary; import org.axonframework.queryhandling.QueryHandler; import org.springframework.stereotype.Component; @@ -17,11 +17,9 @@ public OrderQueriesHandler(OrderRepository ordersRepository) { @QueryHandler public OrderSummary findOrder(FindOrderQuery findOrderQuery) { - Order order = ordersRepository.findByOrderId(findOrderQuery.getOrderId()); return OrderSummary.builder() .orderId(findOrderQuery.getOrderId()) - .orderStatus(order.getOrderStatus()) - .reason(order.getReasonToRejectedOrder()) + .orderStatus(OrderStatus.ORDER_PLACED.toString()) .build(); } diff --git a/order-service/src/main/java/com.nashtech.order/repository/FailedOrderRepository.java b/order-service/src/main/java/com.nashtech.order/repository/FailedOrderRepository.java new file mode 100644 index 00000000..47a4d475 --- /dev/null +++ b/order-service/src/main/java/com.nashtech.order/repository/FailedOrderRepository.java @@ -0,0 +1,8 @@ +package com.nashtech.order.repository; + +import com.nashtech.order.repository.entity.FailedOrder; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FailedOrderRepository extends JpaRepository { + FailedOrder findByOrderId(String orderId); +} diff --git a/order-service/src/main/java/com/nashtech/order/repository/OrderLookupRepository.java b/order-service/src/main/java/com.nashtech.order/repository/OrderLookupRepository.java similarity index 100% rename from order-service/src/main/java/com/nashtech/order/repository/OrderLookupRepository.java rename to order-service/src/main/java/com.nashtech.order/repository/OrderLookupRepository.java diff --git a/order-service/src/main/java/com/nashtech/order/repository/OrderRepository.java b/order-service/src/main/java/com.nashtech.order/repository/OrderRepository.java similarity index 100% rename from order-service/src/main/java/com/nashtech/order/repository/OrderRepository.java rename to order-service/src/main/java/com.nashtech.order/repository/OrderRepository.java diff --git a/order-service/src/main/java/com.nashtech.order/repository/entity/FailedOrder.java b/order-service/src/main/java/com.nashtech.order/repository/entity/FailedOrder.java new file mode 100644 index 00000000..76da6273 --- /dev/null +++ b/order-service/src/main/java/com.nashtech.order/repository/entity/FailedOrder.java @@ -0,0 +1,25 @@ +package com.nashtech.order.repository.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity(name = "failed_orders") +public class FailedOrder { + @Id + private String orderId; + private String userId; + private String productId; + private String paymentId; + private String shipmentId; + private Date timestamp = new Date(); + private String reasonToFailed; + private String orderStatus; +} diff --git a/order-service/src/main/java/com/nashtech/order/repository/entity/Order.java b/order-service/src/main/java/com.nashtech.order/repository/entity/Order.java similarity index 64% rename from order-service/src/main/java/com/nashtech/order/repository/entity/Order.java rename to order-service/src/main/java/com.nashtech.order/repository/entity/Order.java index 8e798897..32560562 100644 --- a/order-service/src/main/java/com/nashtech/order/repository/entity/Order.java +++ b/order-service/src/main/java/com.nashtech.order/repository/entity/Order.java @@ -2,27 +2,24 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; -import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; + import java.util.Date; @Data @AllArgsConstructor @NoArgsConstructor -@Entity -@Table(name = "orders") +@Entity(name = "orders") public class Order { @Id private String orderId; - private String carId; private String userId; - private Double price; - private Integer quantity; + private String productId; + private String paymentId; + private String shipmentId; + private Date timestamp = new Date(); private String orderStatus; - private Date timestamp; - private String reasonToRejectedOrder; - } \ No newline at end of file diff --git a/order-service/src/main/java/com/nashtech/order/repository/entity/OrderLookup.java b/order-service/src/main/java/com.nashtech.order/repository/entity/OrderLookup.java similarity index 85% rename from order-service/src/main/java/com/nashtech/order/repository/entity/OrderLookup.java rename to order-service/src/main/java/com.nashtech.order/repository/entity/OrderLookup.java index 54d1b1f7..47ed51d5 100644 --- a/order-service/src/main/java/com/nashtech/order/repository/entity/OrderLookup.java +++ b/order-service/src/main/java/com.nashtech.order/repository/entity/OrderLookup.java @@ -2,10 +2,10 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; -import jakarta.persistence.Table; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; + import java.util.Date; @@ -13,7 +13,6 @@ @NoArgsConstructor @AllArgsConstructor @Entity -@Table(name = "order_lookup") public class OrderLookup { @Id private String orderId; diff --git a/order-service/src/main/java/com/nashtech/order/api/OrdersCommandController.java b/order-service/src/main/java/com.nashtech.order/restapi/OrdersCommandController.java similarity index 87% rename from order-service/src/main/java/com/nashtech/order/api/OrdersCommandController.java rename to order-service/src/main/java/com.nashtech.order/restapi/OrdersCommandController.java index c89517d8..f8e37003 100644 --- a/order-service/src/main/java/com/nashtech/order/api/OrdersCommandController.java +++ b/order-service/src/main/java/com.nashtech.order/restapi/OrdersCommandController.java @@ -1,10 +1,10 @@ -package com.nashtech.order.api; +package com.nashtech.order.restapi; -import com.nashtech.order.api.request.OrderCreateRequest; -import com.nashtech.order.api.response.OrderSummary; import com.nashtech.order.commands.CreateOrderCommand; import com.nashtech.order.query.FindOrderQuery; +import com.nashtech.order.restapi.request.OrderCreateRequest; +import com.nashtech.order.restapi.response.OrderSummary; import org.axonframework.commandhandling.gateway.CommandGateway; import org.axonframework.messaging.responsetypes.ResponseTypes; import org.axonframework.queryhandling.QueryGateway; @@ -36,9 +36,8 @@ public OrderSummary createOrder(@Valid @RequestBody OrderCreateRequest orderRequ String orderId = UUID.randomUUID().toString(); CreateOrderCommand createOrderCommand = CreateOrderCommand.builder() - .carId(orderRequest.getCarId()).userId(orderRequest.getUserId()) + .productId(orderRequest.getProductId()).userId(orderRequest.getUserId()) .quantity(orderRequest.getQuantity()).orderId(orderId) - .price(orderRequest.getPrice()) .build(); try (SubscriptionQueryResult queryResult = queryGateway.subscriptionQuery( diff --git a/order-service/src/main/java/com/nashtech/order/api/request/OrderCreateRequest.java b/order-service/src/main/java/com.nashtech.order/restapi/request/OrderCreateRequest.java similarity index 71% rename from order-service/src/main/java/com/nashtech/order/api/request/OrderCreateRequest.java rename to order-service/src/main/java/com.nashtech.order/restapi/request/OrderCreateRequest.java index a17a2f78..7636c290 100644 --- a/order-service/src/main/java/com/nashtech/order/api/request/OrderCreateRequest.java +++ b/order-service/src/main/java/com.nashtech.order/restapi/request/OrderCreateRequest.java @@ -1,9 +1,8 @@ -package com.nashtech.order.api.request; +package com.nashtech.order.restapi.request; import lombok.Builder; import lombok.Data; -import javax.validation.constraints.DecimalMin; import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; @@ -12,7 +11,7 @@ public class OrderCreateRequest { @NotBlank(message = "Order carId is a required field") - private String carId; + private String productId; @Min(value = 1, message = "Quantity cannot be lower than 1") private Integer quantity; @@ -20,7 +19,4 @@ public class OrderCreateRequest { @NotBlank(message = "UserId is a required field") private String userId; - @DecimalMin(value = "1.0") - private Double price; - } \ No newline at end of file diff --git a/order-service/src/main/java/com/nashtech/order/api/response/OrderSummary.java b/order-service/src/main/java/com.nashtech.order/restapi/response/OrderSummary.java similarity index 67% rename from order-service/src/main/java/com/nashtech/order/api/response/OrderSummary.java rename to order-service/src/main/java/com.nashtech.order/restapi/response/OrderSummary.java index 8b6c4926..2c78a6d4 100644 --- a/order-service/src/main/java/com/nashtech/order/api/response/OrderSummary.java +++ b/order-service/src/main/java/com.nashtech.order/restapi/response/OrderSummary.java @@ -1,4 +1,4 @@ -package com.nashtech.order.api.response; +package com.nashtech.order.restapi.response; import lombok.Builder; import lombok.Data; @@ -8,6 +8,6 @@ public class OrderSummary { private String orderId; private String orderStatus; - private String reason; + private String message; } \ No newline at end of file diff --git a/order-service/src/main/java/com/nashtech/order/saga/OrderSaga.java b/order-service/src/main/java/com.nashtech.order/saga/OrderSaga.java similarity index 50% rename from order-service/src/main/java/com/nashtech/order/saga/OrderSaga.java rename to order-service/src/main/java/com.nashtech.order/saga/OrderSaga.java index 00891c68..1a60d9e9 100644 --- a/order-service/src/main/java/com/nashtech/order/saga/OrderSaga.java +++ b/order-service/src/main/java/com.nashtech.order/saga/OrderSaga.java @@ -1,27 +1,17 @@ package com.nashtech.order.saga; -import com.nashtech.common.command.ApproveOrderCommand; -import com.nashtech.common.command.CancelPaymentCommand; -import com.nashtech.common.command.CancelProductReserveCommand; -import com.nashtech.common.command.ProcessPaymentCommand; -import com.nashtech.common.command.ReserveProductCommand; -import com.nashtech.common.command.ShipmentOrderCommand; -import com.nashtech.common.event.OrderShippedEvent; -import com.nashtech.common.event.PaymentApprovedEvent; -import com.nashtech.common.event.PaymentCancelledEvent; -import com.nashtech.common.event.ProductReserveCancelledEvent; -import com.nashtech.common.event.ProductReservedEvent; -import com.nashtech.common.event.ShipmentCancelledEvent; -import com.nashtech.common.model.PaymentDetails; -import com.nashtech.common.model.User; +import com.nashtech.common.command.*; +import com.nashtech.common.event.*; import com.nashtech.common.utils.OderFailure; import com.nashtech.common.utils.OrderStatus; -import com.nashtech.order.api.response.OrderSummary; +import com.nashtech.order.commands.ApproveOrderCommand; import com.nashtech.order.commands.RejectOrderCommand; import com.nashtech.order.events.OrderApprovedEvent; import com.nashtech.order.events.OrderCancelledEvent; import com.nashtech.order.events.OrderCreatedEvent; +import com.nashtech.order.exception.CompensateOrder; import com.nashtech.order.query.FindOrderQuery; +import com.nashtech.order.restapi.response.OrderSummary; import lombok.extern.slf4j.Slf4j; import org.axonframework.commandhandling.gateway.CommandGateway; import org.axonframework.modelling.saga.EndSaga; @@ -54,9 +44,8 @@ private void handle(OrderCreatedEvent orderCreatedEvent) { log.info("Order Saga started for Order Id : {}", orderCreatedEvent.getOrderId()); ReserveProductCommand reserveProductCommand = ReserveProductCommand.builder() - .productId(orderCreatedEvent.getCarId()) + .productId(orderCreatedEvent.getProductId()) .orderId(orderCreatedEvent.getOrderId()) - .basePrice(orderCreatedEvent.getPrice()) .quantity(orderCreatedEvent.getQuantity()) .userId(orderCreatedEvent.getUserId()) .build(); @@ -64,91 +53,128 @@ private void handle(OrderCreatedEvent orderCreatedEvent) { commandGateway.send(reserveProductCommand, (commandMessage, commandResultMessage) -> { if (commandResultMessage.isExceptional()) { // Start a compensating transaction - handleCompensatingTransaction(commandResultMessage.exceptionResult().getMessage(), - reserveProductCommand.getOrderId(), OderFailure.INVENTORY_SERVICE_NOT_AVAILABLE.toString()); + CompensateOrder compensateOrder = new CompensateOrder(); + compensateOrder.setOrderId(reserveProductCommand.getOrderId()); + compensateOrder.setProductId(orderCreatedEvent.getProductId()); + compensateOrder.setUserId(orderCreatedEvent.getUserId()); + compensateOrder.setReasonToFailed(OderFailure.INVENTORY_SERVICE_NOT_AVAILABLE.toString()); + compensateOrder.setErrorMessage(commandResultMessage.exceptionResult().getMessage()); + handleCompensatingTransaction(compensateOrder); } }); } @SagaEventHandler(associationProperty = "orderId") public void handle(ProductReservedEvent productReservedEvent) { - // Process user payment - log.info(String.format("ProductReservedEvent is called for productId: %s and orderId: %s ", + log.info(String.format("ProductReservedEvent started for productId: %s and orderId: %s ", productReservedEvent.getProductId(), productReservedEvent.getOrderId())); - //Hard coded User and payment details - PaymentDetails paymentDetails = PaymentDetails.builder() - .bank("SBI") - .cardNumber("0900987654435443") - .validUntilYear(2028) - .validUntilMonth(6) - .cvv(334) - .build(); - ProcessPaymentCommand processPaymentCommand = ProcessPaymentCommand.builder() .paymentId(UUID.randomUUID().toString()) // payment Id generation .orderId(productReservedEvent.getOrderId()) + .userId(productReservedEvent.getUserId()) .productId(productReservedEvent.getProductId()) - .userDetails(addUser(productReservedEvent.getUserId())) - .paymentDetails(paymentDetails) - .price(productReservedEvent.getPrice()) .quantity(productReservedEvent.getQuantity()) + .tax(productReservedEvent.getTax()) + .baseAmount(productReservedEvent.getBaseAmount()) .build(); commandGateway.send(processPaymentCommand, (commandMessage, commandResultMessage) -> { if (commandResultMessage.isExceptional()) { // Start a compensating transaction - handleCompensatingTransaction(commandResultMessage.exceptionResult().getMessage(), - processPaymentCommand.getOrderId(), OderFailure.PAYMENT_SERVICE_NOT_AVAILABLE.toString()); + CompensateOrder compensateOrder = new CompensateOrder(); + compensateOrder.setOrderId(productReservedEvent.getOrderId()); + compensateOrder.setProductId(productReservedEvent.getProductId()); + compensateOrder.setUserId(productReservedEvent.getUserId()); + compensateOrder.setPaymentId(processPaymentCommand.getPaymentId()); + compensateOrder.setReasonToFailed(OderFailure.PAYMENT_SERVICE_NOT_AVAILABLE.toString()); + compensateOrder.setErrorMessage(commandResultMessage.exceptionResult().getMessage()); + handleCompensatingTransaction(compensateOrder); } }); } @SagaEventHandler(associationProperty = "orderId") private void handle(ProductReserveCancelledEvent productReserveCancelledEvent) { - log.info("ProductReserveCancelledEvent is occurred for orderId : {}", productReserveCancelledEvent.getOrderId()); + log.info("ProductReserveCancelledEvent started for orderId : {}", productReserveCancelledEvent.getOrderId()); + // Start the compensating transaction + CompensateOrder compensateOrder = new CompensateOrder(); + compensateOrder.setOrderId(productReserveCancelledEvent.getOrderId()); + compensateOrder.setProductId(productReserveCancelledEvent.getProductId()); + compensateOrder.setUserId(productReserveCancelledEvent.getUserId()); + compensateOrder.setReasonToFailed(productReserveCancelledEvent.getReasonToFailed()); + + handleCompensatingTransaction(compensateOrder); + } + @SagaEventHandler(associationProperty = "orderId") + private void handle(ProductReserveFailedEvent productReserveFailedEvent) { + log.info("ProductReserveFailedEvent started for productId : {}", productReserveFailedEvent.getProductId()); // Start the compensating transaction - orderRejectedCommand(productReserveCancelledEvent.getOrderId(), productReserveCancelledEvent.getReasonToFailed()); + CompensateOrder compensateOrder = new CompensateOrder(); + compensateOrder.setOrderId(productReserveFailedEvent.getOrderId()); + compensateOrder.setProductId(productReserveFailedEvent.getProductId()); + compensateOrder.setUserId(productReserveFailedEvent.getUserId()); + compensateOrder.setReasonToFailed(productReserveFailedEvent.getReasonToFailed()); + + handleCompensatingTransaction(compensateOrder); } @SagaEventHandler(associationProperty = "orderId") private void handle(PaymentApprovedEvent paymentApprovedEvent) { - // log.info(String.format("ProductReservedEvent is called for productId: %s and orderId: %s " - log.info("PaymentProcessedEvent is called for paymentId : {}", paymentApprovedEvent.getPaymentId()); - ShipmentOrderCommand shipmentOrderCommand = ShipmentOrderCommand.builder() + log.info("PaymentProcessedEvent started for paymentId : {}", paymentApprovedEvent.getPaymentId()); + + CreateShipmentCommand createShipmentCommand = CreateShipmentCommand.builder() .shipmentId(UUID.randomUUID().toString()) //Shipment Id generation - .user(addUser(paymentApprovedEvent.getUserId())) + .paymentId(paymentApprovedEvent.getPaymentId()) + .user(paymentApprovedEvent.getUser()) .orderId(paymentApprovedEvent.getOrderId()) .productId(paymentApprovedEvent.getProductId()) - .price(paymentApprovedEvent.getPrice()) + .total(paymentApprovedEvent.getTotal()) + .subTotal(paymentApprovedEvent.getSubTotal()) + .tax(paymentApprovedEvent.getTax()) .quantity(paymentApprovedEvent.getQuantity()) + .basePrice(paymentApprovedEvent.getBasePrice()) .build(); - commandGateway.send(shipmentOrderCommand, (commandMessage, commandResultMessage) -> { + commandGateway.send(createShipmentCommand, (commandMessage, commandResultMessage) -> { if (commandResultMessage.isExceptional()) { // Start the compensating transaction String errorMessage = commandResultMessage.exceptionResult().getMessage(); log.error("PaymentProcessedEvent unable to process shipment due to {}", errorMessage); - handleCompensatingTransaction(errorMessage, shipmentOrderCommand.getOrderId(), - OderFailure.SHIPMENT_SERVICE_NOT_AVAILABLE.toString()); + CompensateOrder compensateOrder = new CompensateOrder(); + compensateOrder.setOrderId(paymentApprovedEvent.getOrderId()); + compensateOrder.setProductId(paymentApprovedEvent.getProductId()); + compensateOrder.setUserId(paymentApprovedEvent.getUser().getUserId()); + compensateOrder.setPaymentId(paymentApprovedEvent.getPaymentId()); + compensateOrder.setShipmentId(createShipmentCommand.getShipmentId()); + compensateOrder.setReasonToFailed(OderFailure.SHIPMENT_SERVICE_NOT_AVAILABLE.toString()); + compensateOrder.setErrorMessage(commandResultMessage.exceptionResult().getMessage()); + handleCompensatingTransaction(compensateOrder); } }); } @SagaEventHandler(associationProperty = "orderId") private void handle(PaymentCancelledEvent paymentCancelledEvent) { - log.info("Payment in not approved!"); + log.info("Payment is not approved!"); // Start a compensating transaction CancelProductReserveCommand cancelProductReserveCommand = CancelProductReserveCommand.builder() .orderId(paymentCancelledEvent.getOrderId()) .productId(paymentCancelledEvent.getProductId()) .quantity(paymentCancelledEvent.getQuantity()) .userId(paymentCancelledEvent.getUserId()) - .reasonToFailed(paymentCancelledEvent.getReason()) + .reasonToFailed(paymentCancelledEvent.getReasonToFailed()) .build(); commandGateway.send(cancelProductReserveCommand); - orderRejectedCommand(paymentCancelledEvent.getOrderId(), paymentCancelledEvent.getReason()); + + CompensateOrder compensateOrder = new CompensateOrder(); + compensateOrder.setOrderId(paymentCancelledEvent.getOrderId()); + compensateOrder.setProductId(paymentCancelledEvent.getProductId()); + compensateOrder.setPaymentId(paymentCancelledEvent.getPaymentId()); + compensateOrder.setUserId(paymentCancelledEvent.getUserId()); + compensateOrder.setReasonToFailed(paymentCancelledEvent.getReasonToFailed()); + handleCompensatingTransaction(compensateOrder); } @SagaEventHandler(associationProperty = "orderId") @@ -156,7 +182,9 @@ public void handle(OrderShippedEvent orderShippedEvent) { log.info("OrderShippedEvent started for order approval"); ApproveOrderCommand approveOrderCommand = ApproveOrderCommand.builder() .orderId(orderShippedEvent.getOrderId()) - .orderStatus(OrderStatus.ORDER_APPROVED) + .paymentId(orderShippedEvent.getPaymentId()) + .shipmentId(orderShippedEvent.getShipmentId()) + .orderStatus(OrderStatus.ORDER_PLACED) .build(); commandGateway.send(approveOrderCommand); } @@ -185,7 +213,14 @@ private void handle(ShipmentCancelledEvent shipmentCancelledEvent) { .build(); commandGateway.send(cancelProductReserveCommand); - orderRejectedCommand(shipmentCancelledEvent.getOrderId(), shipmentCancelledEvent.getReasonToFailed()); + CompensateOrder compensateOrder = new CompensateOrder(); + compensateOrder.setOrderId(shipmentCancelledEvent.getOrderId()); + compensateOrder.setProductId(shipmentCancelledEvent.getProductId()); + compensateOrder.setPaymentId(shipmentCancelledEvent.getPaymentId()); + compensateOrder.setShipmentId(shipmentCancelledEvent.getShipmentId()); + compensateOrder.setUserId(shipmentCancelledEvent.getUserId()); + compensateOrder.setReasonToFailed(shipmentCancelledEvent.getReasonToFailed()); + handleCompensatingTransaction(compensateOrder); } @SagaEventHandler(associationProperty = "orderId") @@ -195,6 +230,8 @@ public void on(OrderApprovedEvent event) { OrderSummary orderSummary = OrderSummary.builder() .orderId(event.getOrderId()) .orderStatus(event.getOrderStatus().toString()) + .message("Thank you for your order! We’ll let you know as soon as it ships. " + + "You can track your order here,review us here, or shop again here.") .build(); queryUpdateEmitter.emit(FindOrderQuery.class, query -> true, orderSummary); } @@ -206,36 +243,32 @@ public void handle(OrderCancelledEvent event) { OrderSummary orderSummary = OrderSummary.builder() .orderId(event.getOrderId()) .orderStatus(event.getOrderStatus().toString()) - .reason(event.getReason()) + .message(event.getReasonToFailed()) .build(); queryUpdateEmitter.emit(FindOrderQuery.class, query -> true, orderSummary); } - private void orderRejectedCommand(String orderId, String reason) { + private void orderRejectedCommand(CompensateOrder compensateOrder,String reason) { RejectOrderCommand rejectOrderCommand = RejectOrderCommand.builder() - .orderId(orderId) - .orderStatus(OrderStatus.ORDER_REJECTED) - .reasonToReject(reason) + .orderId(compensateOrder.getOrderId()) + .userId(compensateOrder.getUserId()) + .reasonToFailed(reason) + .paymentId(compensateOrder.getPaymentId()) + .shipmentId(compensateOrder.getShipmentId()) + .orderStatus(OrderStatus.ORDER_NOT_APPROVED) + .productId(compensateOrder.getProductId()) .build(); commandGateway.send(rejectOrderCommand); } - private void handleCompensatingTransaction(String errorMessage, String orderId, String reason) { - log.error("The resulted is exception {} . Initiating a compensating transaction", errorMessage); - if (errorMessage != null && errorMessage.contains("No Handler for command:")) { - orderRejectedCommand(orderId, reason); + private void handleCompensatingTransaction(CompensateOrder compensateOrder) { + log.error("The resulted is exception {} . Initiating a compensating transaction", compensateOrder.getErrorMessage()); + if (compensateOrder.getErrorMessage() != null && + compensateOrder.getErrorMessage().contains("No Handler for command:")) { + orderRejectedCommand(compensateOrder, compensateOrder.getErrorMessage()); } else { - orderRejectedCommand(orderId, errorMessage); + orderRejectedCommand(compensateOrder,compensateOrder.getReasonToFailed()); } } - private User addUser(String userId) { - return User.builder() - .firstName("Abid") - .lastName("Khan") - .address("Noida") - .userId(userId) - .build(); - } - } diff --git a/order-service/src/main/java/com/nashtech/order/events/handler/OrderEventsHandler.java b/order-service/src/main/java/com/nashtech/order/events/handler/OrderEventsHandler.java deleted file mode 100644 index 1dd26baf..00000000 --- a/order-service/src/main/java/com/nashtech/order/events/handler/OrderEventsHandler.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.nashtech.order.events.handler; - -import com.nashtech.common.utils.OrderStatus; -import com.nashtech.order.events.OrderApprovedEvent; -import com.nashtech.order.events.OrderCancelledEvent; -import com.nashtech.order.events.OrderCreatedEvent; -import com.nashtech.order.repository.OrderRepository; -import com.nashtech.order.repository.entity.Order; -import lombok.extern.slf4j.Slf4j; -import org.axonframework.config.ProcessingGroup; -import org.axonframework.eventhandling.EventHandler; -import org.axonframework.messaging.interceptors.ExceptionHandler; -import org.springframework.stereotype.Component; - -import java.util.Date; - -@Component -@ProcessingGroup("order-group") -@Slf4j -public class OrderEventsHandler { - - private final OrderRepository orderRepository; - - public OrderEventsHandler(OrderRepository orderRepository) { - this.orderRepository = orderRepository; - } - - @EventHandler - public void on(OrderCreatedEvent event) { - Order order = new Order(event.getOrderId(), event.getCarId(), event.getUserId(), event.getPrice(), - event.getQuantity(), event.getOrderStatus().toString(), new Date(), null); - orderRepository.save(order); - } - - @EventHandler - public void on(OrderApprovedEvent orderApprovedEvent) { - Order order = orderRepository.findByOrderId((orderApprovedEvent.getOrderId())); - order.setOrderStatus(OrderStatus.ORDER_APPROVED.toString()); - orderRepository.save(order); - } - - @EventHandler - public void on(OrderCancelledEvent event) { - Order order = orderRepository.findByOrderId((event.getOrderId())); - order.setOrderStatus(event.getOrderStatus().toString()); - order.setReasonToRejectedOrder(event.getReason()); - orderRepository.save(order); - } - - @ExceptionHandler - public void handle(Exception exception) throws Exception { - log.error("{} occurred during order saving", exception.getMessage()); - throw exception; - } - -} diff --git a/order-service/src/main/resources/application.yml b/order-service/src/main/resources/application.yml index 69665cc5..bbef586f 100644 --- a/order-service/src/main/resources/application.yml +++ b/order-service/src/main/resources/application.yml @@ -2,12 +2,12 @@ server: port: 9090 spring: application: - name: OrderService + name: OrderService datasource: - url: jdbc:mysql://${MYSQL_HOST:localhost}:3306/orders_db + url: jdbc:mysql://${MYSQL_HOST:localhost}:3306/order_db driverClassName: com.mysql.cj.jdbc.Driver - username: ${MYSQL_DB_USERNAME} - password: ${MYSQL_DB_PASSWORD} + username: ${MYSQL_DB_USERNAME:root} + password: ${MYSQL_DB_PASSWORD:password} jpa: database-platform: org.hibernate.dialect.MySQL8Dialect hibernate: @@ -20,9 +20,4 @@ axon: mode: subscribing axonserver: client-id: OrderService - servers: ${AXON_HOST} -# Possible values for these keys are `default`, `xstream`, `java`, and `jackson`. - serializer: - general: default - events: jackson - messages: jackson + servers: ${AXON_HOST:localhost:8124} diff --git a/order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java b/order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java index 48628fed..69c3c420 100644 --- a/order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java +++ b/order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java @@ -6,4 +6,8 @@ @SpringBootTest class OrderServiceApplicationTests { + @Test + void contextLoads() { + } + } diff --git a/payment-service/app-config.yaml b/payment-service/app-config.yaml new file mode 100644 index 00000000..8512510f --- /dev/null +++ b/payment-service/app-config.yaml @@ -0,0 +1,8 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: payment-configmap +data: + # Configuration values can be set as key-value properties + MYSQL_HOST: 35.231.178.113 + AXON_HOST: 34.23.126.183:8124 diff --git a/payment-service/deployment.yaml b/payment-service/deployment.yaml index a62d4cd1..bce08e15 100644 --- a/payment-service/deployment.yaml +++ b/payment-service/deployment.yaml @@ -22,3 +22,19 @@ spec: - name: http containerPort: 9092 protocol: TCP + env: + - name: MYSQL_DB_USERNAME + valueFrom: + secretKeyRef: + name: secret-to-be-created + key: mysql-db-username + optional: false + - name: MYSQL_DB_PASSWORD + valueFrom: + secretKeyRef: + name: secret-to-be-created + key: mysql-db-userpassword + optional: false + envFrom: + - configMapRef: + name: payment-configmap diff --git a/payment-service/kustomization.yaml b/payment-service/kustomization.yaml index 42a42ff1..4809c39a 100644 --- a/payment-service/kustomization.yaml +++ b/payment-service/kustomization.yaml @@ -2,6 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: +- secretstore.yaml +- app-config.yaml - service.yaml - deployment.yaml diff --git a/payment-service/pom.xml b/payment-service/pom.xml index 86575a44..9d2fddca 100644 --- a/payment-service/pom.xml +++ b/payment-service/pom.xml @@ -11,8 +11,7 @@ com.nashtech.payment payment-service 1.0.0 - PaymentService - Demo project for Spring Boot + payment-service diff --git a/payment-service/secretstore.yaml b/payment-service/secretstore.yaml new file mode 100644 index 00000000..9da9c54a --- /dev/null +++ b/payment-service/secretstore.yaml @@ -0,0 +1,42 @@ +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: car-demo-payment-secretstore + namespace: default +spec: + provider: + gcpsm: + auth: + secretRef: + secretAccessKeySecretRef: + name: gcpsm-secret + key: secret-access-credentials + projectID: boreal-gravity-396810 +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: car-demo-externalsecret + namespace: default +spec: + secretStoreRef: + name: car-demo-payment-secretstore + kind: SecretStore + target: + name: secret-to-be-created + data: + - secretKey: "mysql-db-username" + remoteRef: + key: car-demo-secret + version: latest + property: mysql-db-username + - secretKey: "mysql-db-userpassword" + remoteRef: + key: car-demo-secret + version: latest + property: mysql-db-userpassword + + - secretKey: "MY_SQL_SECRETS" + remoteRef: + key: car-demo-secret + version: latest \ No newline at end of file diff --git a/payment-service/src/main/java/com/nashtech/payment/PaymentServiceApplication.java b/payment-service/src/main/java/com.nashtech.payment/PaymentServiceApplication.java similarity index 53% rename from payment-service/src/main/java/com/nashtech/payment/PaymentServiceApplication.java rename to payment-service/src/main/java/com.nashtech.payment/PaymentServiceApplication.java index d39d93da..46af5afd 100644 --- a/payment-service/src/main/java/com/nashtech/payment/PaymentServiceApplication.java +++ b/payment-service/src/main/java/com.nashtech.payment/PaymentServiceApplication.java @@ -1,16 +1,12 @@ package com.nashtech.payment; -import com.nashtech.payment.config.AxonXstreamConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Import; @SpringBootApplication -@Import({ AxonXstreamConfig.class }) public class PaymentServiceApplication { - public static void main(String[] args) { - SpringApplication.run(com.nashtech.payment.PaymentServiceApplication.class, args); + SpringApplication.run(PaymentServiceApplication.class, args); } } diff --git a/payment-service/src/main/java/com.nashtech.payment/aggregate/PaymentAggregate.java b/payment-service/src/main/java/com.nashtech.payment/aggregate/PaymentAggregate.java new file mode 100644 index 00000000..d0ffd3aa --- /dev/null +++ b/payment-service/src/main/java/com.nashtech.payment/aggregate/PaymentAggregate.java @@ -0,0 +1,111 @@ +package com.nashtech.payment.aggregate; + +import com.nashtech.common.command.ProcessPaymentCommand; +import com.nashtech.common.event.PaymentApprovedEvent; +import com.nashtech.common.event.PaymentCancelledEvent; +import com.nashtech.common.model.PaymentDetails; +import com.nashtech.common.model.User; +import lombok.extern.slf4j.Slf4j; +import org.axonframework.commandhandling.CommandHandler; +import org.axonframework.eventsourcing.EventSourcingHandler; +import org.axonframework.modelling.command.AggregateIdentifier; +import org.axonframework.modelling.command.AggregateLifecycle; +import org.axonframework.spring.stereotype.Aggregate; + +@Aggregate +@Slf4j +public class PaymentAggregate { + + @AggregateIdentifier + private String paymentId; + private String orderId; + private String productId; + private Integer quantity; + private Double price; + private User user; + private String reasonToFailed; + private String reason; + private Double baseAmount; + + public PaymentAggregate() { + } + + @CommandHandler + public PaymentAggregate(ProcessPaymentCommand processPaymentCommand) { + log.info("ProcessPaymentCommand started"); + User paymentUser = getUser(); + PaymentDetails paymentDetails = getPaymentDetails(); + + if (!processPaymentCommand.getUserId().equals(paymentUser.getUserId()) + && paymentDetails.getUserId().equals(paymentUser.getUserId())) { + AggregateLifecycle.apply(buildPaymentCancelEvent(processPaymentCommand,"User does not exist")); + return; + } + + double subTotal = processPaymentCommand.getQuantity() * processPaymentCommand.getBaseAmount(); + double total = subTotal + (processPaymentCommand.getQuantity() * processPaymentCommand.getTax()); + + if (paymentDetails.getBalanceAmount() <= total) { + AggregateLifecycle.apply(buildPaymentCancelEvent(processPaymentCommand,"Insufficient Amount")); + return; + } + + PaymentApprovedEvent paymentApprovedEvent = + PaymentApprovedEvent.builder() + .paymentId(processPaymentCommand.getPaymentId()) + .orderId(processPaymentCommand.getOrderId()) + .productId(processPaymentCommand.getProductId()) + .user(paymentUser) + .quantity(processPaymentCommand.getQuantity()) + .subTotal(subTotal) + .total(total) + .tax(processPaymentCommand.getTax()) + .basePrice(processPaymentCommand.getBaseAmount()) + .build(); + AggregateLifecycle.apply(paymentApprovedEvent); + } + + @EventSourcingHandler + public void on(PaymentApprovedEvent paymentApprovedEvent) { + this.paymentId = paymentApprovedEvent.getPaymentId(); + this.orderId = paymentApprovedEvent.getOrderId(); + this.productId = paymentApprovedEvent.getProductId(); + this.quantity = paymentApprovedEvent.getQuantity(); + this.user = paymentApprovedEvent.getUser(); + } + + //Hard coded User details + private User getUser() { + return User.builder() + .userId("1652") + .firstName("Abid") + .lastName("Khan") + .address("Noida") + .mobileNumber("9087658765") + .emailId("abid.khan@nashtechglobal.com") + .build(); + } + + //Hard coded payment details + private PaymentDetails getPaymentDetails() { + return PaymentDetails.builder() + .userId("1652") + .bank("SBI") + .cardNumber("0900987654435443") + .validUntilYear(2028) + .validUntilMonth(6) + .cvv(334) + .balanceAmount(10000000d) //1Cr + .build(); + } + + private PaymentCancelledEvent buildPaymentCancelEvent(ProcessPaymentCommand processPaymentCommand, String reasonToFailed) { + return PaymentCancelledEvent.builder() + .paymentId(processPaymentCommand.getPaymentId()) + .orderId(processPaymentCommand.getOrderId()) + .userId(processPaymentCommand.getUserId()) + .reasonToFailed(reasonToFailed) + .build(); + } + +} diff --git a/payment-service/src/main/java/com/nashtech/payment/config/AxonXstreamConfig.java b/payment-service/src/main/java/com.nashtech.payment/config/AxonXStreamConfig.java similarity index 92% rename from payment-service/src/main/java/com/nashtech/payment/config/AxonXstreamConfig.java rename to payment-service/src/main/java/com.nashtech.payment/config/AxonXStreamConfig.java index 90d90a83..25ee811a 100644 --- a/payment-service/src/main/java/com/nashtech/payment/config/AxonXstreamConfig.java +++ b/payment-service/src/main/java/com.nashtech.payment/config/AxonXStreamConfig.java @@ -6,7 +6,7 @@ import org.springframework.context.annotation.Configuration; @Configuration -public class AxonXstreamConfig { +public class AxonXStreamConfig { @Bean public XStream xStream() { @@ -15,4 +15,5 @@ public XStream xStream() { return xStream; } + } diff --git a/payment-service/src/main/java/com/nashtech/payment/data/Payment.java b/payment-service/src/main/java/com.nashtech.payment/data/Payment.java similarity index 64% rename from payment-service/src/main/java/com/nashtech/payment/data/Payment.java rename to payment-service/src/main/java/com.nashtech.payment/data/Payment.java index d2eea372..dca9f90d 100644 --- a/payment-service/src/main/java/com/nashtech/payment/data/Payment.java +++ b/payment-service/src/main/java/com.nashtech.payment/data/Payment.java @@ -1,8 +1,5 @@ package com.nashtech.payment.data; -import com.nashtech.common.model.PaymentDetails; -import com.nashtech.common.model.PaymentStatus; -import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; @@ -24,9 +21,9 @@ public class Payment { private String orderId; private String productId; private String quantity; - private Double price; - private String userId; - private PaymentDetails paymentDetails; - private PaymentStatus paymentStatus; + private Double baseAmount; + private Double subTotal; + private Double total; + private Float tax; } diff --git a/payment-service/src/main/java/com/nashtech/payment/data/PaymentsRepository.java b/payment-service/src/main/java/com.nashtech.payment/data/PaymentsRepository.java similarity index 99% rename from payment-service/src/main/java/com/nashtech/payment/data/PaymentsRepository.java rename to payment-service/src/main/java/com.nashtech.payment/data/PaymentsRepository.java index 5f0cf266..b41042c4 100644 --- a/payment-service/src/main/java/com/nashtech/payment/data/PaymentsRepository.java +++ b/payment-service/src/main/java/com.nashtech.payment/data/PaymentsRepository.java @@ -5,4 +5,5 @@ public interface PaymentsRepository extends JpaRepository { Payment findByOrderId(String orderId); + } diff --git a/payment-service/src/main/java/com/nashtech/payment/events/handler/PaymentsEventHandler.java b/payment-service/src/main/java/com.nashtech.payment/handler/PaymentsEventHandler.java similarity index 66% rename from payment-service/src/main/java/com/nashtech/payment/events/handler/PaymentsEventHandler.java rename to payment-service/src/main/java/com.nashtech.payment/handler/PaymentsEventHandler.java index 6deaf1a4..1b4d5907 100644 --- a/payment-service/src/main/java/com/nashtech/payment/events/handler/PaymentsEventHandler.java +++ b/payment-service/src/main/java/com.nashtech.payment/handler/PaymentsEventHandler.java @@ -1,17 +1,15 @@ -package com.nashtech.payment.events.handler; +package com.nashtech.payment.handler; import com.nashtech.common.event.PaymentApprovedEvent; import com.nashtech.payment.data.Payment; import com.nashtech.payment.data.PaymentsRepository; +import lombok.extern.slf4j.Slf4j; import org.axonframework.eventhandling.EventHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component +@Slf4j public class PaymentsEventHandler { - - private final Logger LOGGER = LoggerFactory.getLogger(PaymentsEventHandler.class); private PaymentsRepository paymentsRepository; public PaymentsEventHandler(PaymentsRepository paymentsRepository) { @@ -20,18 +18,19 @@ public PaymentsEventHandler(PaymentsRepository paymentsRepository) { @EventHandler public void on(PaymentApprovedEvent paymentApprovedEvent){ - - LOGGER.info("PaymentProcessedEvent is called for orderId:{} ", paymentApprovedEvent.getOrderId()); + log.info("PaymentProcessedEvent is called for orderId:{} ", paymentApprovedEvent.getOrderId()); Payment payment = Payment.builder() .paymentId(paymentApprovedEvent.getPaymentId()) .orderId(paymentApprovedEvent.getOrderId()) .productId(paymentApprovedEvent.getProductId()) .quantity(String.valueOf(paymentApprovedEvent.getQuantity())) - .price(paymentApprovedEvent.getPrice()) - .userId(paymentApprovedEvent.getUserId()) - .paymentStatus(paymentApprovedEvent.getPaymentStatus()) + .baseAmount(paymentApprovedEvent.getBasePrice()) + .subTotal(paymentApprovedEvent.getSubTotal()) + .tax(paymentApprovedEvent.getTax()) + .total(paymentApprovedEvent.getTotal()) .build(); paymentsRepository.save(payment); } + } diff --git a/payment-service/src/main/java/com/nashtech/payment/command/aggregate/PaymentAggregate.java b/payment-service/src/main/java/com/nashtech/payment/command/aggregate/PaymentAggregate.java deleted file mode 100644 index e6b29972..00000000 --- a/payment-service/src/main/java/com/nashtech/payment/command/aggregate/PaymentAggregate.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.nashtech.payment.command.aggregate; - -import com.nashtech.common.command.ProcessPaymentCommand; - -import com.nashtech.common.event.PaymentApprovedEvent; -import com.nashtech.common.event.PaymentCancelledEvent; -import lombok.extern.slf4j.Slf4j; -import org.axonframework.commandhandling.CommandHandler; -import org.axonframework.eventsourcing.EventSourcingHandler; -import org.axonframework.modelling.command.AggregateIdentifier; -import org.axonframework.modelling.command.AggregateLifecycle; -import org.axonframework.spring.stereotype.Aggregate; - -@Aggregate -@Slf4j -public class PaymentAggregate { - - @AggregateIdentifier - private String paymentId; - private String orderId; - private String productId; - private Integer quantity; - private Double price; - private String userId; - private String reasonToFailed; - private String paymentStatus; - private String reason; - - public PaymentAggregate() { - } - @CommandHandler - public PaymentAggregate(ProcessPaymentCommand processPaymentCommand) { - - if(processPaymentCommand.getPrice() <= 0) { - - PaymentCancelledEvent paymentCancelledEvent = PaymentCancelledEvent.builder() - .paymentId(processPaymentCommand.getPaymentId()) - .orderId(processPaymentCommand.getOrderId()) - .userId(processPaymentCommand.getUserDetails().getUserId()) - .reason("Insufficient Amount").build(); - - AggregateLifecycle.apply(paymentCancelledEvent); - - return; - } - - PaymentApprovedEvent paymentApprovedEvent = - PaymentApprovedEvent.builder() - .orderId(processPaymentCommand.getOrderId()) - .paymentId(processPaymentCommand.getPaymentId()) - .productId(processPaymentCommand.getProductId()) - .price(processPaymentCommand.getPrice()) - .quantity(processPaymentCommand.getQuantity()) - .paymentStatus(processPaymentCommand.getPaymentStatus()) - .build(); - - AggregateLifecycle.apply(paymentApprovedEvent); - } - - @EventSourcingHandler - public void on(PaymentApprovedEvent paymentApprovedEvent){ - this.paymentId = paymentApprovedEvent.getPaymentId(); - this.orderId = paymentApprovedEvent.getOrderId(); - this.productId = paymentApprovedEvent.getProductId(); - this.quantity = paymentApprovedEvent.getQuantity(); - this.price = paymentApprovedEvent.getPrice(); - this.userId = paymentApprovedEvent.getUserId(); - this.paymentStatus = String.valueOf(paymentApprovedEvent.getPaymentStatus()); - } - -} diff --git a/payment-service/src/main/resources/application.yml b/payment-service/src/main/resources/application.yml index dc2385a5..8da5d319 100644 --- a/payment-service/src/main/resources/application.yml +++ b/payment-service/src/main/resources/application.yml @@ -2,12 +2,12 @@ server: port: 9092 spring: application: - name: PaymentService + name: PaymentService datasource: - url: jdbc:mysql://${MYSQL_HOST:localhost}:3306/payment_db?createDatabaseIfNotExist=true + url: jdbc:mysql://${MYSQL_HOST:localhost}:3306/payment_db driverClassName: com.mysql.cj.jdbc.Driver - username: ${DB_USER} - password: ${DB_PASSWORD} + username: ${MYSQL_DB_USERNAME:root} + password: ${MYSQL_DB_PASSWORD:password} jpa: database-platform: org.hibernate.dialect.MySQLDialect hibernate: @@ -16,4 +16,4 @@ spring: axon: axonserver: client-id: PaymentService - servers: ${AXON_HOST} \ No newline at end of file + servers: ${AXON_HOST:localhost:8124} diff --git a/payment-service/src/test/java/com/nashtech/payment/PaymentMircoserviceApplicationTests.java b/payment-service/src/test/java/com/nashtech/payment/PaymentMircoserviceApplicationTests.java index 59d3469e..288d1cfd 100644 --- a/payment-service/src/test/java/com/nashtech/payment/PaymentMircoserviceApplicationTests.java +++ b/payment-service/src/test/java/com/nashtech/payment/PaymentMircoserviceApplicationTests.java @@ -6,4 +6,8 @@ @SpringBootTest class PaymentMircoserviceApplicationTests { + @Test + void contextLoads() { + } + } diff --git a/shipment-service/app-config.yaml b/shipment-service/app-config.yaml new file mode 100644 index 00000000..71b8171c --- /dev/null +++ b/shipment-service/app-config.yaml @@ -0,0 +1,8 @@ +kind: ConfigMap +apiVersion: v1 +metadata: + name: shipment-configmap +data: + # Configuration values can be set as key-value properties + MYSQL_HOST: 35.231.178.113 + AXON_HOST: 34.23.126.183:8124 diff --git a/shipment-service/deployment.yaml b/shipment-service/deployment.yaml index 4392cf3a..5b3bea68 100644 --- a/shipment-service/deployment.yaml +++ b/shipment-service/deployment.yaml @@ -22,3 +22,19 @@ spec: - name: http containerPort: 9093 protocol: TCP + env: + - name: MYSQL_DB_USERNAME + valueFrom: + secretKeyRef: + name: secret-to-be-created + key: mysql-db-username + optional: false + - name: MYSQL_DB_PASSWORD + valueFrom: + secretKeyRef: + name: secret-to-be-created + key: mysql-db-userpassword + optional: false + envFrom: + - configMapRef: + name: shipment-configmap \ No newline at end of file diff --git a/shipment-service/kustomization.yaml b/shipment-service/kustomization.yaml index 42a42ff1..4809c39a 100644 --- a/shipment-service/kustomization.yaml +++ b/shipment-service/kustomization.yaml @@ -2,6 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: +- secretstore.yaml +- app-config.yaml - service.yaml - deployment.yaml diff --git a/shipment-service/pom.xml b/shipment-service/pom.xml index 597128ef..7f26fe42 100644 --- a/shipment-service/pom.xml +++ b/shipment-service/pom.xml @@ -11,8 +11,7 @@ com.nashtech.shipment shipment-service 1.0.0 - ShipmentService - Demo project for Spring Boot + shipment-service @@ -43,6 +42,8 @@ 8.0.33 4.8.1 1.0.1 + 4.7.2 + 2022.0.4 @@ -64,6 +65,10 @@ mysql-connector-j ${mysql-connector.version} + + com.google.cloud + spring-cloud-gcp-starter-pubsub + org.springframework.boot spring-boot-starter-test @@ -75,8 +80,37 @@ ${common.version} compile + + javax.inject + javax.inject + 1 + + + com.fasterxml.jackson.core + jackson-databind + 2.15.2 + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + com.google.cloud + spring-cloud-gcp-dependencies + ${spring-cloud-gcp.version} + pom + import + + + + diff --git a/shipment-service/secretstore.yaml b/shipment-service/secretstore.yaml new file mode 100644 index 00000000..42ef7250 --- /dev/null +++ b/shipment-service/secretstore.yaml @@ -0,0 +1,42 @@ +apiVersion: external-secrets.io/v1beta1 +kind: SecretStore +metadata: + name: car-demo-shipment-secretstore + namespace: default +spec: + provider: + gcpsm: + auth: + secretRef: + secretAccessKeySecretRef: + name: gcpsm-secret + key: secret-access-credentials + projectID: boreal-gravity-396810 +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: car-demo-externalsecret + namespace: default +spec: + secretStoreRef: + name: car-demo-shipment-secretstore + kind: SecretStore + target: + name: secret-to-be-created + data: + - secretKey: "mysql-db-username" + remoteRef: + key: car-demo-secret + version: latest + property: mysql-db-username + - secretKey: "mysql-db-userpassword" + remoteRef: + key: car-demo-secret + version: latest + property: mysql-db-userpassword + + - secretKey: "MY_SQL_SECRETS" + remoteRef: + key: car-demo-secret + version: latest \ No newline at end of file diff --git a/shipment-service/src/main/java/com/nashtech/shipment/ShipmentServiceApplication.java b/shipment-service/src/main/java/com/nashtech/shipment/ShipmentServiceApplication.java index ef5d2c65..37cdc083 100644 --- a/shipment-service/src/main/java/com/nashtech/shipment/ShipmentServiceApplication.java +++ b/shipment-service/src/main/java/com/nashtech/shipment/ShipmentServiceApplication.java @@ -1,15 +1,13 @@ package com.nashtech.shipment; -import com.nashtech.shipment.config.AxonXstreamConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Import; @SpringBootApplication -@Import({ AxonXstreamConfig.class }) public class ShipmentServiceApplication { public static void main(String[] args) { SpringApplication.run(ShipmentServiceApplication.class, args); } + } diff --git a/shipment-service/src/main/java/com/nashtech/shipment/aggregate/ShipmentAggregate.java b/shipment-service/src/main/java/com/nashtech/shipment/aggregate/ShipmentAggregate.java index 4aa5fdc8..985417d2 100644 --- a/shipment-service/src/main/java/com/nashtech/shipment/aggregate/ShipmentAggregate.java +++ b/shipment-service/src/main/java/com/nashtech/shipment/aggregate/ShipmentAggregate.java @@ -1,58 +1,72 @@ package com.nashtech.shipment.aggregate; -import com.nashtech.common.command.CreatedShipmentCommand; +import com.nashtech.common.command.CreateShipmentCommand; +import com.nashtech.common.event.OrderShippedEvent; import com.nashtech.common.event.ShipmentCreatedEvent; -import com.nashtech.common.model.ShipmentStatus; +import com.nashtech.common.model.User; +import lombok.extern.slf4j.Slf4j; import org.axonframework.commandhandling.CommandHandler; import org.axonframework.eventsourcing.EventSourcingHandler; import org.axonframework.modelling.command.AggregateIdentifier; import org.axonframework.modelling.command.AggregateLifecycle; import org.axonframework.spring.stereotype.Aggregate; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @Aggregate +@Slf4j public class ShipmentAggregate { - private final Logger LOGGER = LoggerFactory.getLogger(ShipmentAggregate.class); - @AggregateIdentifier private String shipmentId; private String orderId; + private String paymentId; private String productId; private Integer quantity; - private Double price; - private String userId; - private String paymentId; - private ShipmentStatus shipmentStatus; + private Double basePrice; + private Double subTotal; + private Double total; + private Float tax; + private User user; public ShipmentAggregate() { } @CommandHandler - public ShipmentAggregate(CreatedShipmentCommand createdShipmentCommand) { - LOGGER.info("CreatedShipmentCommand is called for shipmentId: {}", createdShipmentCommand.getShipmentId()); + public ShipmentAggregate(CreateShipmentCommand createShipmentCommand) { + log.info("CreateShipmentCommand is called for shipmentId: {}", createShipmentCommand.getShipmentId()); ShipmentCreatedEvent shipmentCreatedEvent = ShipmentCreatedEvent.builder() - .shipmentId(createdShipmentCommand.getShipmentId()) - .orderId(createdShipmentCommand.getOrderId()) - .productId(createdShipmentCommand.getProductId()) - .quantity(createdShipmentCommand.getQuantity()) - .price(createdShipmentCommand.getPrice()) - .userId(createdShipmentCommand.getUserId()) - .paymentId(createdShipmentCommand.getPaymentId()) - .shipmentStatus(createdShipmentCommand.getShipmentStatus()).build(); + .shipmentId(createShipmentCommand.getShipmentId()) + .orderId(createShipmentCommand.getOrderId()) + .paymentId(createShipmentCommand.getPaymentId()) + .productId(createShipmentCommand.getProductId()) + .quantity(createShipmentCommand.getQuantity()) + .basePrice(createShipmentCommand.getBasePrice()) + .tax(createShipmentCommand.getTax()) + .subTotal(createShipmentCommand.getSubTotal()) + .total(createShipmentCommand.getTotal()) + .user(createShipmentCommand.getUser()) + .build(); AggregateLifecycle.apply(shipmentCreatedEvent); + + OrderShippedEvent shippedEvent = OrderShippedEvent.builder() + .orderId(createShipmentCommand.getOrderId()) + .paymentId(createShipmentCommand.getPaymentId()) + .shipmentId(createShipmentCommand.getShipmentId()) + .build(); + AggregateLifecycle.apply(shippedEvent); } @EventSourcingHandler public void on(ShipmentCreatedEvent shipmentCreatedEvent) { this.shipmentId = shipmentCreatedEvent.getShipmentId(); this.orderId = shipmentCreatedEvent.getOrderId(); + this.paymentId = shipmentCreatedEvent.getPaymentId(); this.productId = shipmentCreatedEvent.getProductId(); this.quantity = shipmentCreatedEvent.getQuantity(); - this.price = shipmentCreatedEvent.getPrice(); - this.userId = shipmentCreatedEvent.getUserId(); - this.paymentId = shipmentCreatedEvent.getPaymentId(); - this.shipmentStatus = shipmentCreatedEvent.getShipmentStatus(); + this.basePrice = shipmentCreatedEvent.getBasePrice(); + this.subTotal = shipmentCreatedEvent.getSubTotal(); + this.total = shipmentCreatedEvent.getTotal(); + this.tax = shipmentCreatedEvent.getTax(); + this.user = shipmentCreatedEvent.getUser(); } + } diff --git a/shipment-service/src/main/java/com/nashtech/shipment/config/AxonXstreamConfig.java b/shipment-service/src/main/java/com/nashtech/shipment/config/AxonXStreamConfig.java similarity index 92% rename from shipment-service/src/main/java/com/nashtech/shipment/config/AxonXstreamConfig.java rename to shipment-service/src/main/java/com/nashtech/shipment/config/AxonXStreamConfig.java index da5d9b5c..861f7614 100644 --- a/shipment-service/src/main/java/com/nashtech/shipment/config/AxonXstreamConfig.java +++ b/shipment-service/src/main/java/com/nashtech/shipment/config/AxonXStreamConfig.java @@ -6,7 +6,7 @@ import org.springframework.context.annotation.Configuration; @Configuration -public class AxonXstreamConfig { +public class AxonXStreamConfig { @Bean public XStream xStream() { @@ -15,4 +15,5 @@ public XStream xStream() { return xStream; } + } \ No newline at end of file diff --git a/shipment-service/src/main/java/com/nashtech/shipment/entity/ShipmentEntity.java b/shipment-service/src/main/java/com/nashtech/shipment/entity/ShipmentEntity.java index 26a1d183..e32ce3f6 100644 --- a/shipment-service/src/main/java/com/nashtech/shipment/entity/ShipmentEntity.java +++ b/shipment-service/src/main/java/com/nashtech/shipment/entity/ShipmentEntity.java @@ -1,6 +1,5 @@ package com.nashtech.shipment.entity; -import com.nashtech.common.model.ShipmentStatus; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; @@ -17,10 +16,20 @@ public class ShipmentEntity { @Id private String shipmentId; private String orderId; + private String paymentId; + + private String userId; + private String firstName; + private String lastName; + private String address; + private String emailId; + private String mobileNumber; + private String productId; private Integer quantity; - private Double price; - private String userId; - private String paymentId; - private ShipmentStatus shipmentStatus; + private Double basePrice; + private Double subTotal; + private Double total; + private Float tax; + } diff --git a/shipment-service/src/main/java/com/nashtech/shipment/handler/ShipmentEventHandler.java b/shipment-service/src/main/java/com/nashtech/shipment/handler/ShipmentEventHandler.java index ffddf114..b7348b58 100644 --- a/shipment-service/src/main/java/com/nashtech/shipment/handler/ShipmentEventHandler.java +++ b/shipment-service/src/main/java/com/nashtech/shipment/handler/ShipmentEventHandler.java @@ -1,36 +1,52 @@ package com.nashtech.shipment.handler; import com.nashtech.common.event.ShipmentCreatedEvent; +import com.nashtech.common.model.User; import com.nashtech.shipment.entity.ShipmentEntity; import com.nashtech.shipment.repository.ShipmentRepository; +import com.nashtech.shipment.service.PubSubPublisherService; +import lombok.extern.slf4j.Slf4j; import org.axonframework.eventhandling.EventHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component +@Slf4j public class ShipmentEventHandler { - private final Logger LOGGER = LoggerFactory.getLogger(ShipmentEventHandler.class); private final ShipmentRepository shipmentRepository; + private final PubSubPublisherService pubSubPublisherService; - public ShipmentEventHandler(ShipmentRepository shipmentRepository) { + public ShipmentEventHandler(ShipmentRepository shipmentRepository, PubSubPublisherService pubSubPublisherService) { this.shipmentRepository = shipmentRepository; + this.pubSubPublisherService = pubSubPublisherService; } @EventHandler public void on(ShipmentCreatedEvent shipmentCreatedEvent) { - LOGGER.info("ShipmentCreatedEvent is called for shipmentId: {}", shipmentCreatedEvent.getShipmentId()); + log.info("ShipmentCreatedEvent is called for shipmentId: {}", shipmentCreatedEvent.getShipmentId()); + User user = shipmentCreatedEvent.getUser(); ShipmentEntity shipmentEntity = new ShipmentEntity( shipmentCreatedEvent.getShipmentId(), shipmentCreatedEvent.getOrderId(), + shipmentCreatedEvent.getPaymentId(), + user.getUserId(), + user.getFirstName(), + user.getLastName(), + user.getAddress(), + user.getEmailId(), + user.getMobileNumber(), shipmentCreatedEvent.getProductId(), shipmentCreatedEvent.getQuantity(), - shipmentCreatedEvent.getPrice(), - shipmentCreatedEvent.getUserId(), - shipmentCreatedEvent.getPaymentId(), - shipmentCreatedEvent.getShipmentStatus() + shipmentCreatedEvent.getBasePrice(), + shipmentCreatedEvent.getSubTotal(), + shipmentCreatedEvent.getTotal(), + shipmentCreatedEvent.getTax() ); + log.info("Saving Shipment details to database"); shipmentRepository.save(shipmentEntity); + + log.info("Sending Shipment details to pub sub topic"); + pubSubPublisherService.messagePublisher(shipmentEntity); } + } diff --git a/shipment-service/src/main/java/com/nashtech/shipment/repository/ShipmentRepository.java b/shipment-service/src/main/java/com/nashtech/shipment/repository/ShipmentRepository.java index 71f142c3..b4c4a0d9 100644 --- a/shipment-service/src/main/java/com/nashtech/shipment/repository/ShipmentRepository.java +++ b/shipment-service/src/main/java/com/nashtech/shipment/repository/ShipmentRepository.java @@ -5,4 +5,5 @@ public interface ShipmentRepository extends JpaRepository { ShipmentEntity findByOrderId(String orderId); + } diff --git a/shipment-service/src/main/java/com/nashtech/shipment/service/PubSubPublisherService.java b/shipment-service/src/main/java/com/nashtech/shipment/service/PubSubPublisherService.java new file mode 100644 index 00000000..bca0c945 --- /dev/null +++ b/shipment-service/src/main/java/com/nashtech/shipment/service/PubSubPublisherService.java @@ -0,0 +1,68 @@ +package com.nashtech.shipment.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.google.api.core.ApiFuture; +import com.google.cloud.pubsub.v1.Publisher; +import com.google.protobuf.ByteString; +import com.google.pubsub.v1.PubsubMessage; +import com.google.pubsub.v1.TopicName; +import com.nashtech.shipment.entity.ShipmentEntity; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +@Service +@Slf4j +public class PubSubPublisherService { + private Publisher publisher; + + @Value("${pubSub.project-id}") + private String projectId; + + @Value("${pubSub.topic-id}") + private String topicId; + + private ObjectMapper objectMapper; + + @PostConstruct + public void init() throws IOException { + TopicName topicName = TopicName.of(projectId, topicId); + publisher = Publisher.newBuilder(topicName).build(); + objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + } + + @PreDestroy + public void cleanup() { + try { + if (publisher != null) { + publisher.shutdown(); + publisher.awaitTermination(1, TimeUnit.MINUTES); + } + } catch (InterruptedException interruptedException) { + log.error("Error while shutting down Publisher: {}", + interruptedException.getMessage()); + } + } + + + public void messagePublisher(final ShipmentEntity shipmentEntity) { + log.info("Publishing data to topic: {}", topicId); + + try { + String shipmentData = objectMapper.writeValueAsString(shipmentEntity); + PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8(shipmentData)).build(); + ApiFuture publishedMessage = publisher.publish(pubsubMessage); + log.info("Message id generated:{}", publishedMessage.get()); + } catch (Exception exception) { + log.error("Error : {} while publishing data to pub sub topic : {}", exception.getMessage(), topicId); + } + } + +} diff --git a/shipment-service/src/main/resources/application.yml b/shipment-service/src/main/resources/application.yml index 456e6591..43f946ea 100644 --- a/shipment-service/src/main/resources/application.yml +++ b/shipment-service/src/main/resources/application.yml @@ -2,12 +2,12 @@ server: port: 9093 spring: application: - name: ShipmentService + name: ShipmentService datasource: - url: jdbc:mysql://${MYSQL_HOST:127.0.0.1}:3306/shipment_db + url: jdbc:mysql://${MYSQL_HOST:localhost}:3306/shipment_db driverClassName: com.mysql.cj.jdbc.Driver - username: ${DB_USER} - password: ${DB_PASSWORD} + username: ${MYSQL_DB_USERNAME:root} + password: ${MYSQL_DB_PASSWORD:password} jpa: database-platform: org.hibernate.dialect.MySQL8Dialect hibernate: @@ -16,4 +16,8 @@ spring: axon: axonserver: client-id: ShipmentService - servers: ${AXON_HOST} + servers: ${AXON_HOST:localhost:8124} + +pubsub: + project-id: ${GCP_PROJECT_ID} + topic-id: ${PUB_SUB_TOPIC_ID}