Skip to content

Commit

Permalink
Merge pull request #3 from charansingh83sh/order-service
Browse files Browse the repository at this point in the history
Added Cancel order API and tests
  • Loading branch information
charansingh83sh committed Oct 28, 2020
2 parents df6d97b + 944904c commit 210665f
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 20 deletions.
13 changes: 4 additions & 9 deletions CustomerService/Service/CustomerDataService.cs
Expand Up @@ -36,30 +36,26 @@ public Customer CreateCustomer(String name, Money creditLimit)
}
public void ReserveCredit(long orderId, long customerId, Money orderTotal)
{

Customer customer = customerRepository.FindById(customerId);
if (customer == null)
{
var customerValidationFailedEvent = new CustomerValidationFailedEvent(orderId);
List<IDomainEvent> eventList = new List<IDomainEvent>();
eventList.Add(customerValidationFailedEvent);
eventList.Add(new CustomerValidationFailedEvent(orderId));
domainEventPublisher.Publish(typeof(Customer).Name, customerId, eventList);
return;
}
try
{
var creditReservation = customer.ReserveCredit(orderId, orderTotal);
customerRepository.Add(creditReservation);
CustomerCreditReservedEvent customerCreditReservedEvent = new CustomerCreditReservedEvent(orderId);
List<IDomainEvent> eventList = new List<IDomainEvent>();
eventList.Add(customerCreditReservedEvent);
eventList.Add(new CustomerCreditReservedEvent(orderId));
domainEventPublisher.Publish(typeof(Customer).Name, customer.Id, eventList);
}
catch (CustomerCreditLimitExceededException)
{
CustomerCreditReservationFailedEvent customerCreditReservationFailedEvent = new CustomerCreditReservationFailedEvent(orderId);
List<IDomainEvent> eventList = new List<IDomainEvent>();
eventList.Add(customerCreditReservationFailedEvent);
eventList.Add(new CustomerCreditReservationFailedEvent(orderId));
domainEventPublisher.Publish(typeof(Customer).Name, customer.Id, eventList);
}
}
Expand All @@ -68,9 +64,8 @@ public void ReleaseCredit(long orderId, long customerId)
Customer customer = customerRepository.FindById(customerId);
if (customer == null)
{
var customerValidationFailedEvent = new CustomerValidationFailedEvent(orderId);
List<IDomainEvent> eventList = new List<IDomainEvent>();
eventList.Add(customerValidationFailedEvent);
eventList.Add(new CustomerValidationFailedEvent(orderId));
domainEventPublisher.Publish(typeof(Customer).Name, customerId, eventList);
return;
}
Expand Down
6 changes: 5 additions & 1 deletion CustomerService/Service/OrderEventConsumer.cs
Expand Up @@ -9,7 +9,7 @@

namespace CustomerService.Service
{
public class OrderEventConsumer : IDomainEventHandler<OrderCreatedEvent>
public class OrderEventConsumer : IDomainEventHandler<OrderCreatedEvent>, IDomainEventHandler<OrderCancelledEvent>
{
private readonly ILogger logger;
private CustomerDataService customerService;
Expand All @@ -22,6 +22,10 @@ public void Handle(IDomainEventEnvelope<OrderCreatedEvent> orderCreatedEvent)
{
customerService.ReserveCredit(Convert.ToInt32(orderCreatedEvent.AggregateId), orderCreatedEvent.Event.OrderDetails.CustomerId, orderCreatedEvent.Event.OrderDetails.OrderTotal);
}
public void Handle(IDomainEventEnvelope<OrderCancelledEvent> orderCancelledEvent)
{
customerService.ReleaseCredit(Convert.ToInt32(orderCancelledEvent.AggregateId), orderCancelledEvent.Event.OrderDetails.CustomerId);
}

}
}
1 change: 1 addition & 0 deletions CustomerService/Startup.cs
Expand Up @@ -57,6 +57,7 @@ public void ConfigureServices(IServiceCollection services)
services.AddEventuateTramDomainEventDispatcher(Guid.NewGuid().ToString(),
provider => DomainEventHandlersBuilder.ForAggregateType("Order")
.OnEvent<OrderCreatedEvent, OrderEventConsumer>()
.OnEvent<OrderCancelledEvent, OrderEventConsumer>()
.Build());
// Repository
services.AddTransient<ICustomerRepository, CustomerRepository>();
Expand Down
21 changes: 21 additions & 0 deletions EndToEndTests/CustomersAndOrdersEndToEndTest.cs
Expand Up @@ -40,6 +40,22 @@ public void ShouldReject()
Assert.IsNotNull(orderId);
AssertOrderState(orderId, OrderState.REJECTED);
}
[TestMethod]
public void ShouldRejectForNonExistentCustomerId()
{
long customerId = System.DateTime.Today.Ticks;
long orderId = CreateOrder(customerId, "120.50");
AssertOrderState(orderId, OrderState.REJECTED);
}
[TestMethod]
public void ShouldCancel()
{
long customerId = CreateCustomer("Joe", "50.30");
long orderId = CreateOrder(customerId, "20.50");
AssertOrderState(orderId, OrderState.APPROVED);
CancelOrder(orderId);
AssertOrderState(orderId, OrderState.CANCELLED);
}
private long CreateCustomer(string name, string amount)
{
CreateCustomerRequest request = new CreateCustomerRequest();
Expand All @@ -56,6 +72,11 @@ private long CreateOrder(long customerId, string amount)
var orderResponse = WebApiHelper.WebApiCall<CreateOrderResponse>("POST", urlOrder, JsonSerializer.Serialize(request));
return orderResponse.OrderId;
}
private void CancelOrder(long orderId)
{
var orderResponse = WebApiHelper.WebApiCall<GetOrderResponse>("POST", urlOrder + "/" + orderId + "/cancel", null);
}

private void AssertOrderState(long orderId, OrderState orderState)
{
Util.Eventually(100, 1000, () =>
Expand Down
10 changes: 10 additions & 0 deletions OrderService/Classes/PendingOrderCantBeCancelledException.cs
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace OrderService.Classes
{
class PendingOrderCantBeCancelledException : Exception
{
}
}
8 changes: 8 additions & 0 deletions OrderService/Controllers/OrderController.cs
Expand Up @@ -39,5 +39,13 @@ public IActionResult GetOrder([FromRoute] long id)
GetOrderResponse getOrderResponse = new GetOrderResponse(order.Id, order.OrderDetails, order.State, order.Version);
return Ok(getOrderResponse);
}
[HttpPost]
[Route("{id:long}/cancel")]
public IActionResult CancelOrder([FromRoute] long id)
{
Order order = orderService.CancelOrder(id);
CreateOrderResponse createOrderResponse = new CreateOrderResponse(order.Id);
return Ok(createOrderResponse);
}
}
}
26 changes: 26 additions & 0 deletions OrderService/Models/Order.cs
@@ -1,4 +1,5 @@
using IO.Eventuate.Tram.Events.Common;
using OrderService.Classes;
using ServiceCommon.Classes;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -26,5 +27,30 @@ public Order(OrderDetails orderDetails)
OrderDetails = orderDetails;
State = OrderState.PENDING;
}
public Order NoteCreditReserved()
{
this.State = OrderState.APPROVED;
return this;
}

public Order NoteCreditReservationFailed()
{
this.State = OrderState.REJECTED;
return this;
}
public Order Cancel()
{
switch (State)
{
case OrderState.PENDING:
throw new PendingOrderCantBeCancelledException();
case OrderState.APPROVED:
this.State = OrderState.CANCELLED;
return this;
default:
throw new InvalidOperationException("Can't cancel in this state: " + State);
}
}

}
}
31 changes: 21 additions & 10 deletions OrderService/Service/OrderDataService.cs
Expand Up @@ -40,11 +40,10 @@ public void ApproveOrder(long orderId)
{
throw new System.ArgumentException(string.Format("Order with id {0} not found", orderId));
}
order.State = OrderState.APPROVED;
order = order.NoteCreditReserved();
orderRepository.Update(order);
List<IDomainEvent> eventList = new List<IDomainEvent>();
var orderApprovedEvent = new OrderApprovedEvent(order.OrderDetails);
eventList.Add(orderApprovedEvent);
eventList.Add(new OrderApprovedEvent(order.OrderDetails));
domainEventPublisher.Publish(typeof(Order).Name, order.Id, eventList);
}
public void RejectOrder(long orderId)
Expand All @@ -54,24 +53,36 @@ public void RejectOrder(long orderId)
{
throw new System.ArgumentException(string.Format("Order with id {0} not found", orderId));
}
order.State = OrderState.REJECTED;
order = order.NoteCreditReservationFailed();
orderRepository.Update(order);
List<IDomainEvent> eventList = new List<IDomainEvent>();
var orderRejectedEvent = new OrderRejectedEvent(order.OrderDetails);
eventList.Add(orderRejectedEvent);
eventList.Add(new OrderRejectedEvent(order.OrderDetails));
domainEventPublisher.Publish(typeof(Order).Name, order.Id, eventList);
}
public static ResultsWithEvents Create(OrderDetails orderDetails)
{
Order order = new Order(orderDetails);
var orderCreatedEvent = new OrderCreatedEvent(orderDetails);
List<IDomainEvent> eventList = new List<IDomainEvent>();
eventList.Add(orderCreatedEvent);
eventList.Add(new OrderCreatedEvent(orderDetails));
return new ResultsWithEvents(order, eventList);
}
public Order GetOrder(long id)
public Order GetOrder(long orderId)
{
Order order = orderRepository.FindById(id);
Order order = orderRepository.FindById(orderId);
return order;
}
public Order CancelOrder(long orderId)
{
Order order = orderRepository.FindById(orderId);
if (order == null)
{
throw new System.ArgumentException(string.Format("Order with id {0} not found", orderId));
}
order = order.Cancel();
orderRepository.Update(order);
List<IDomainEvent> eventList = new List<IDomainEvent>();
eventList.Add(new OrderCancelledEvent(order.OrderDetails));
domainEventPublisher.Publish(typeof(Order).Name, order.Id, eventList);
return order;
}
}
Expand Down
21 changes: 21 additions & 0 deletions ServiceCommon/Classes/OrderCancelledEvent.cs
@@ -0,0 +1,21 @@
using IO.Eventuate.Tram.Events.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ServiceCommon.Classes
{
public class OrderCancelledEvent : IDomainEvent
{
public OrderDetails OrderDetails { get; set; }
public OrderCancelledEvent()
{
}
public OrderCancelledEvent(OrderDetails orderDetails)
{
OrderDetails = orderDetails;
}

}
}

0 comments on commit 210665f

Please sign in to comment.