Skip to content
This repository was archived by the owner on Nov 17, 2023. It is now read-only.

Added complete order service #2170

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers;

[Route("api/v1/[controller]")]
[Authorize]

[ApiController]
public class OrderController : ControllerBase
{
Expand Down Expand Up @@ -33,4 +33,15 @@ public async Task<ActionResult<OrderData>> GetOrderDraftAsync(string basketId)

return await _orderingService.GetOrderDraftAsync(basket);
}
[Route("complete")]
[HttpPut]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<CompleteData>> CompleteOrderAsync(string orderId)
{
if (string.IsNullOrWhiteSpace(orderId))
{
return BadRequest("Need a valid orderId");
}
return await _orderingService.CompleteOrderAsync(orderId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{
public class CompleteData
{
public string CompleteStatus { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models
{
public class CompleteRequest
{
public string OrderId { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/ApiGateways/Web.Bff.Shopping/aggregator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

builder.Services.AddReverseProxy(builder.Configuration);
builder.Services.AddControllers();

builder.Services.AddHttpClient<OrderingService>();
builder.Services.AddHealthChecks(builder.Configuration);
builder.Services.AddCors(options =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
public interface IOrderingService
{
Task<OrderData> GetOrderDraftAsync(BasketData basketData);
Task<CompleteData> CompleteOrderAsync(string orderId);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;
using Newtonsoft.Json;
using System.Text;

namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services;

public class OrderingService : IOrderingService
{
private readonly GrpcOrdering.OrderingGrpc.OrderingGrpcClient _orderingGrpcClient;
private readonly ILogger<OrderingService> _logger;
private readonly HttpClient _httpClient;

public OrderingService(GrpcOrdering.OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger)
public OrderingService(GrpcOrdering.OrderingGrpc.OrderingGrpcClient orderingGrpcClient, ILogger<OrderingService> logger, HttpClient httpClient)
{
_orderingGrpcClient = orderingGrpcClient;
_logger = logger;
_httpClient = httpClient;
}

public async Task<OrderData> GetOrderDraftAsync(BasketData basketData)
Expand Down Expand Up @@ -68,5 +73,28 @@ private GrpcOrdering.CreateOrderDraftCommand MapToOrderDraftCommand(BasketData b

return command;
}
/// <summary>
/// CompleteOrderAsync is the endpoint that will be called to indicate that the order is complete.
/// </summary>
/// <param name="orderId">Order number</param>
/// <returns></returns>
public async Task<CompleteData> CompleteOrderAsync(string orderId)
{
// TODO Grpc OrderingGrpc bağlantı servisinde hata alınmaktadır.Bu nedenle httpclient sınıfı kullanılmıştır.
#region OrderingGrpc
CompleteData completeData = new CompleteData();
_logger.LogDebug("CompleteOrderAsync method called with orderId={@orderId}", orderId);

var request = new GrpcOrdering.CompleteOrderCommand
{
OrderId = orderId
};
var response = await _orderingGrpcClient.CompleteOrderAsync(request);

_logger.LogDebug("gRPC CompleteOrder response: {@response}", response);
completeData.CompleteStatus = response.CompleteStatus;
return completeData;
#endregion
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
{
public class CompleteOrderCommand : IRequest<CompleteOrderDTO>
{
public int OrderId { get; set; }
public CompleteOrderCommand(int orderNumber)
{
OrderId = orderNumber;
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
{
public class CompleteOrderCommandHandler : IRequestHandler<CompleteOrderCommand, CompleteOrderDTO>
{
private readonly IOrderRepository _orderRepository; // Varsayılan bir repo

private readonly IMediator _mediator; // Integration event'leri fırlatmak için

public CompleteOrderCommandHandler(IOrderRepository orderRepository, IMediator mediator)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
}

public async Task<CompleteOrderDTO> Handle(CompleteOrderCommand request, CancellationToken cancellationToken)
{

//var order = await _orderRepository.GetOrderAsync(request.OrderId);
CompleteOrderDTO completeStatus = new CompleteOrderDTO();
var order = await _orderRepository.GetAsync(request.OrderId);
if (order == null)
{
completeStatus.CompleteStatus = "Incompleted";
return completeStatus;
}
order.CompleteOrder(); // The status of the order was set to "Complete".

_orderRepository.Update(order);
await _orderRepository.UnitOfWork.SaveChangesAsync(cancellationToken);

await _mediator.Publish(new OrderCompletedIntegrationEvent(order.Id)); //When the process is completed, an integration event is thrown.
completeStatus.CompleteStatus = "Completed";
return completeStatus;
}
}
public class CompleteOrderDTO
{
public string CompleteStatus { get; set; }

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Ordering.Domain.Events;

namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.DomainEventHandlers
{
public class OrderCompletedDomainEventHandler : INotificationHandler<OrderCompletedDomainEvent>
{
private readonly IOrderRepository _orderRepository;
private readonly IBuyerRepository _buyerRepository;
private readonly ILogger _logger;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;

public OrderCompletedDomainEventHandler(
IOrderRepository orderRepository,
ILogger<OrderCompletedDomainEventHandler> logger,
IBuyerRepository buyerRepository,
IOrderingIntegrationEventService orderingIntegrationEventService)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
}

public async Task Handle(OrderCompletedDomainEvent domainEvent, CancellationToken cancellationToken)
{
OrderingApiTrace.LogOrderStatusUpdated(_logger, domainEvent.Order.Id, nameof(OrderStatus.Completed), OrderStatus.Completed.Id);

var order = await _orderRepository.GetAsync(domainEvent.Order.Id);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());

var integrationEvent = new OrderCompletedIntegrationEvent(order.Id);
await _orderingIntegrationEventService.AddAndSaveEventAsync(integrationEvent);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.IntegrationEvents.Events
{
public record OrderCompletedIntegrationEvent : IntegrationEvent
{
public int OrderId { get; }

public OrderCompletedIntegrationEvent(int orderId)
{
OrderId = orderId;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Validations
{
public class CompleteOrderCommandValidator : AbstractValidator<CompleteOrderCommand>
{
public CompleteOrderCommandValidator(ILogger<CompleteOrderCommandValidator> logger)
{
RuleFor(command => command.OrderId)
.GreaterThan(0)
.WithMessage("OrderId should be a positive number.");

logger.LogTrace("INSTANCE CREATED - {ClassName}", GetType().Name);
}
}
}
18 changes: 18 additions & 0 deletions src/Services/Ordering/Ordering.API/Controllers/OrdersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,22 @@ public async Task<ActionResult<OrderDraftDTO>> CreateOrderDraftFromBasketDataAsy

return await _mediator.Send(createOrderDraftCommand);
}

[Route("complete")]
[HttpPut]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<CompleteOrderDTO>> CompleteOrderAsync([FromBody] CompleteOrderCommand command)
{
CompleteOrderDTO completeOrderDTO = new CompleteOrderDTO();
_logger.LogInformation(
"Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
command.GetGenericTypeName(),
nameof(command.OrderId),
command.OrderId,
command);

completeOrderDTO = await _mediator.Send(command);
return completeOrderDTO;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@ await policy.ExecuteAsync(async () =>
var contentRootPath = env.ContentRootPath;


using (context)
{
context.Database.Migrate();

if (!context.CardTypes.Any())
{
context.CardTypes.AddRange(useCustomizationData
? GetCardTypesFromFile(contentRootPath, logger)
: GetPredefinedCardTypes());
//using (context)
//{
context.Database.Migrate();

await context.SaveChangesAsync();
}

if (!context.OrderStatus.Any())
{
context.OrderStatus.AddRange(useCustomizationData
? GetOrderStatusFromFile(contentRootPath, logger)
: GetPredefinedOrderStatus());
}
if (!context.CardTypes.Any())
{
context.CardTypes.AddRange(useCustomizationData
? GetCardTypesFromFile(contentRootPath, logger)
: GetPredefinedCardTypes());

await context.SaveChangesAsync();
}

if (!context.OrderStatus.Any())
{
context.OrderStatus.AddRange(useCustomizationData
? GetOrderStatusFromFile(contentRootPath, logger)
: GetPredefinedOrderStatus());
}

await context.SaveChangesAsync();
//}
});
}

Expand Down Expand Up @@ -115,6 +115,7 @@ private IEnumerable<OrderStatus> GetOrderStatusFromFile(string contentRootPath,
.Where(x => x != null);
}


private OrderStatus CreateOrderStatus(string value, ref int id)
{
if (string.IsNullOrEmpty(value))
Expand Down
9 changes: 7 additions & 2 deletions src/Services/Ordering/Ordering.API/Proto/ordering.proto
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ package OrderingApi;

service OrderingGrpc {
rpc CreateOrderDraftFromBasketData(CreateOrderDraftCommand) returns (OrderDraftDTO) {}
rpc CompleteOrder(CompleteOrderCommand) returns (CompleteOrderDTO) {}
}

message CreateOrderDraftCommand {
string buyerId = 1;
repeated BasketItem items = 2;
}

message CompleteOrderCommand {
string orderId = 1;
}

message BasketItem {
string id = 1;
Expand All @@ -23,11 +26,13 @@ message BasketItem {
int32 quantity = 6;
string pictureUrl = 7;
}

message OrderDraftDTO {
double total = 1;
repeated OrderItemDTO orderItems = 2;
}
message CompleteOrderDTO {
string CompleteStatus = 1;
}
message OrderItemDTO {
int32 productId = 1;
string productName = 2;
Expand Down
3 changes: 2 additions & 1 deletion src/Services/Ordering/Ordering.API/Setup/OrderStatus.csv
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ AwaitingValidation
StockConfirmed
Paid
Shipped
Cancelled
Cancelled
Completed
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Ordering.Domain.Events;

namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;

public class Order
: Entity, IAggregateRoot
Expand Down Expand Up @@ -157,6 +159,19 @@ public void SetCancelledStatus()
_description = $"The order was cancelled.";
AddDomainEvent(new OrderCancelledDomainEvent(this));
}
public void CompleteOrder()
{
if (_orderStatusId == OrderStatus.Shipped.Id ||
_orderStatusId == OrderStatus.Completed.Id)
{
StatusChangeException(OrderStatus.Completed);
}

_orderStatusId = OrderStatus.Cancelled.Id;
_description = $"The order was completed.";
AddDomainEvent(new OrderCompletedDomainEvent(this));
}


public void SetCancelledStatusWhenStockIsRejected(IEnumerable<int> orderStockRejectedItems)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ public class OrderStatus
public static OrderStatus Paid = new OrderStatus(4, nameof(Paid).ToLowerInvariant());
public static OrderStatus Shipped = new OrderStatus(5, nameof(Shipped).ToLowerInvariant());
public static OrderStatus Cancelled = new OrderStatus(6, nameof(Cancelled).ToLowerInvariant());
public static OrderStatus Completed = new OrderStatus(7, nameof(Completed).ToLowerInvariant());

public OrderStatus(int id, string name)
: base(id, name)
{
}

public static IEnumerable<OrderStatus> List() =>
new[] { Submitted, AwaitingValidation, StockConfirmed, Paid, Shipped, Cancelled };
new[] { Submitted, AwaitingValidation, StockConfirmed, Paid, Shipped, Cancelled, Completed };

public static OrderStatus FromName(string name)
{
Expand Down
Loading