Merge branch 'order-processflow-redesign' of https://github.com/dotnet-architecture/eShopOnContainers into order-processflow-redesign
This commit is contained in:
commit
8045d6302b
@ -36,12 +36,9 @@ namespace Ordering.API.Application.DomainEventHandlers.BuyerAndPaymentMethodVeri
|
|||||||
|
|
||||||
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(buyerPaymentMethodVerifiedEvent.Buyer.IdentityGuid);
|
var orderStartedIntegrationEvent = new OrderStartedIntegrationEvent(buyerPaymentMethodVerifiedEvent.Buyer.IdentityGuid);
|
||||||
|
|
||||||
// Using a local transaction to achieve atomicity between original Ordering database operation and
|
|
||||||
// the IntegrationEventLog. Only saving event if order has been successfully persisted to db
|
|
||||||
await _orderingIntegrationEventService
|
await _orderingIntegrationEventService
|
||||||
.SaveEventAndOrderingContextChangesAsync(orderStartedIntegrationEvent);
|
.SaveEventAndOrderingContextChangesAsync(orderStartedIntegrationEvent);
|
||||||
|
|
||||||
// Publish ordering integration event and mark it as published
|
|
||||||
await _orderingIntegrationEventService
|
await _orderingIntegrationEventService
|
||||||
.PublishThroughEventBusAsync(orderStartedIntegrationEvent);
|
.PublishThroughEventBusAsync(orderStartedIntegrationEvent);
|
||||||
|
|
||||||
|
@ -6,23 +6,25 @@
|
|||||||
using Domain.Events;
|
using Domain.Events;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Ordering.API.Application.IntegrationCommands.Commands;
|
||||||
|
using Ordering.API.Application.IntegrationEvents;
|
||||||
|
|
||||||
public class UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler
|
public class UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler
|
||||||
: IAsyncNotificationHandler<OrderStockMethodVerifiedDomainEvent>
|
: IAsyncNotificationHandler<OrderStockMethodVerifiedDomainEvent>
|
||||||
{
|
{
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
private readonly ILoggerFactory _logger;
|
private readonly ILoggerFactory _logger;
|
||||||
|
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
||||||
|
|
||||||
public UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler(
|
public UpdateOrderWhenOrderStockMethodVerifiedDomainEventHandler(
|
||||||
IOrderRepository orderRepository, ILoggerFactory logger)
|
IOrderRepository orderRepository, ILoggerFactory logger,
|
||||||
|
IOrderingIntegrationEventService orderingIntegrationEventService)
|
||||||
{
|
{
|
||||||
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_orderingIntegrationEventService = orderingIntegrationEventService;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Domain Logic comment:
|
|
||||||
// When the Order Stock items method have been validate and confirmed,
|
|
||||||
// then we can update the original Order with the new order status
|
|
||||||
public async Task Handle(OrderStockMethodVerifiedDomainEvent orderStockMethodVerifiedDomainEvent)
|
public async Task Handle(OrderStockMethodVerifiedDomainEvent orderStockMethodVerifiedDomainEvent)
|
||||||
{
|
{
|
||||||
var orderToUpdate = await _orderRepository.GetAsync(orderStockMethodVerifiedDomainEvent.OrderId);
|
var orderToUpdate = await _orderRepository.GetAsync(orderStockMethodVerifiedDomainEvent.OrderId);
|
||||||
@ -37,14 +39,9 @@
|
|||||||
.LogTrace($"Order with Id: {orderStockMethodVerifiedDomainEvent.OrderId} has been successfully updated with " +
|
.LogTrace($"Order with Id: {orderStockMethodVerifiedDomainEvent.OrderId} has been successfully updated with " +
|
||||||
$"a status order id: { orderStockMethodVerifiedDomainEvent.OrderStatus.Id }");
|
$"a status order id: { orderStockMethodVerifiedDomainEvent.OrderStatus.Id }");
|
||||||
|
|
||||||
|
var payOrderCommandMsg = new PayOrderCommandMsg(orderToUpdate.Id);
|
||||||
//var payOrderCommandMsg = new PayOrderCommandMsg(order.Id);
|
await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg);
|
||||||
|
await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg);
|
||||||
//// Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
|
|
||||||
//await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(payOrderCommandMsg);
|
|
||||||
|
|
||||||
//// Publish through the Event Bus and mark the saved event as published
|
|
||||||
//await _orderingIntegrationEventService.PublishThroughEventBusAsync(payOrderCommandMsg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
||||||
|
{
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public class OrderPaymentFailedIntegrationEventHandler :
|
||||||
|
IIntegrationEventHandler<OrderPaymentFailedIntegrationEvent>
|
||||||
|
{
|
||||||
|
public async Task Handle(OrderPaymentFailedIntegrationEvent @event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
||||||
|
{
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public class OrderPaymentSuccededIntegrationEventHandler :
|
||||||
|
IIntegrationEventHandler<OrderPaymentSuccededIntegrationEvent>
|
||||||
|
{
|
||||||
|
public async Task Handle(OrderPaymentSuccededIntegrationEvent @event)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,8 @@
|
|||||||
using Ordering.API.Application.IntegrationCommands.Commands;
|
using Ordering.API.Application.IntegrationCommands.Commands;
|
||||||
using Ordering.Domain.Exceptions;
|
using Ordering.Domain.Exceptions;
|
||||||
|
|
||||||
public class OrderStockConfirmedIntegrationEventHandler : IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>
|
public class OrderStockConfirmedIntegrationEventHandler :
|
||||||
|
IIntegrationEventHandler<OrderStockConfirmedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
|
||||||
private readonly IOrderRepository _orderRepository;
|
private readonly IOrderRepository _orderRepository;
|
||||||
@ -25,7 +26,7 @@
|
|||||||
var order = await _orderRepository.GetAsync(@event.OrderId);
|
var order = await _orderRepository.GetAsync(@event.OrderId);
|
||||||
CheckValidSagaId(order);
|
CheckValidSagaId(order);
|
||||||
|
|
||||||
order.SetOrderStockConfirmed(true);
|
order.SetOrderStockConfirmed();
|
||||||
|
|
||||||
//Create Integration Event to be published through the Event Bus
|
//Create Integration Event to be published through the Event Bus
|
||||||
var payOrderCommandMsg = new PayOrderCommandMsg(order.Id);
|
var payOrderCommandMsg = new PayOrderCommandMsg(order.Id);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
||||||
{
|
{
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using System;
|
using System;
|
||||||
@ -27,14 +29,11 @@
|
|||||||
var order = await _orderRepository.GetAsync(@event.OrderId);
|
var order = await _orderRepository.GetAsync(@event.OrderId);
|
||||||
CheckValidSagaId(order);
|
CheckValidSagaId(order);
|
||||||
|
|
||||||
order.SetOrderStockConfirmed(false);
|
var orderStockNotConfirmedItems = @event.OrderStockItems
|
||||||
|
.FindAll(c => !c.Confirmed)
|
||||||
|
.Select(c => c.ProductId);
|
||||||
|
|
||||||
var orderStockNotConfirmedItems = @event.OrderStockItems.FindAll(c => !c.Confirmed);
|
order.SetOrderStockConfirmed(orderStockNotConfirmedItems);
|
||||||
|
|
||||||
foreach (var orderStockNotConfirmedItem in orderStockNotConfirmedItems)
|
|
||||||
{
|
|
||||||
//TODO: Add messages
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckValidSagaId(Order orderSaga)
|
private void CheckValidSagaId(Order orderSaga)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using MediatR;
|
using System;
|
||||||
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ordering.API.Application.IntegrationEvents.Events;
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.IntegrationEvents.Events
|
||||||
|
{
|
||||||
|
public class OrderPaymentFailedIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public int OrderId { get; }
|
||||||
|
|
||||||
|
public OrderPaymentFailedIntegrationEvent(int orderId) => OrderId = orderId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.IntegrationEvents.Events
|
||||||
|
{
|
||||||
|
public class OrderPaymentSuccededIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public int OrderId { get; }
|
||||||
|
|
||||||
|
public OrderPaymentSuccededIntegrationEvent(int orderId) => OrderId = orderId;
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@
|
|||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
var result = await connection.QueryAsync<dynamic>(
|
var result = await connection.QueryAsync<dynamic>(
|
||||||
@"select o.[Id] as ordernumber,o.OrderDate as date, os.Name as status,
|
@"select o.[Id] as ordernumber,o.OrderDate as date, o.Description as description, os.Name as status,
|
||||||
oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl,
|
oi.ProductName as productname, oi.Units as units, oi.UnitPrice as unitprice, oi.PictureUrl as pictureurl,
|
||||||
a.Street as street, a.City as city, a.Country as country, a.State as state, a.ZipCode as zipcode
|
a.Street as street, a.City as city, a.Country as country, a.State as state, a.ZipCode as zipcode
|
||||||
FROM ordering.Orders o
|
FROM ordering.Orders o
|
||||||
@ -75,6 +75,7 @@
|
|||||||
order.ordernumber = result[0].ordernumber;
|
order.ordernumber = result[0].ordernumber;
|
||||||
order.date = result[0].date;
|
order.date = result[0].date;
|
||||||
order.status = result[0].status;
|
order.status = result[0].status;
|
||||||
|
order.description = result[0].description;
|
||||||
order.street = result[0].street;
|
order.street = result[0].street;
|
||||||
order.city = result[0].city;
|
order.city = result[0].city;
|
||||||
order.zipcode = result[0].zipcode;
|
order.zipcode = result[0].zipcode;
|
||||||
|
@ -50,7 +50,7 @@ namespace Ordering.API.Application.Sagas
|
|||||||
/// has been completed and order has not been cancelled.
|
/// has been completed and order has not been cancelled.
|
||||||
/// If so, the process continues for validation.
|
/// If so, the process continues for validation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="command">
|
/// <param name="event">
|
||||||
/// Integration command message which is sent by a saga
|
/// Integration command message which is sent by a saga
|
||||||
/// scheduler which provides the sagas that its grace
|
/// scheduler which provides the sagas that its grace
|
||||||
/// period has completed.
|
/// period has completed.
|
||||||
@ -69,10 +69,10 @@ namespace Ordering.API.Application.Sagas
|
|||||||
var orderStockList = orderSaga.OrderItems
|
var orderStockList = orderSaga.OrderItems
|
||||||
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
|
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
|
||||||
|
|
||||||
//Create Integration Event to be published through the Event Bus
|
|
||||||
var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderSaga.Id, orderStockList);
|
var confirmOrderStockEvent = new ConfirmOrderStockCommandMsg(orderSaga.Id, orderStockList);
|
||||||
|
|
||||||
// Publish through the Event Bus and mark the saved event as published
|
await _orderingIntegrationEventService.SaveEventAndOrderingContextChangesAsync(confirmOrderStockEvent);
|
||||||
|
|
||||||
await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent);
|
await _orderingIntegrationEventService.PublishThroughEventBusAsync(confirmOrderStockEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,246 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||||
|
|
||||||
|
namespace Ordering.API.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(OrderingContext))]
|
||||||
|
[Migration("20170511112333_AddOrderDescription")]
|
||||||
|
partial class AddOrderDescription
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.1.1")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:ordering.paymentseq", "'paymentseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "buyerseq")
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<string>("IdentityGuid")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("IdentityGuid")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("buyers","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasDefaultValue(1);
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("cardtypes","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "paymentseq")
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<string>("Alias")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
b.Property<int>("BuyerId");
|
||||||
|
|
||||||
|
b.Property<string>("CardHolderName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
b.Property<string>("CardNumber")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(25);
|
||||||
|
|
||||||
|
b.Property<int>("CardTypeId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expiration");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BuyerId");
|
||||||
|
|
||||||
|
b.HasIndex("CardTypeId");
|
||||||
|
|
||||||
|
b.ToTable("paymentmethods","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("City");
|
||||||
|
|
||||||
|
b.Property<string>("Country");
|
||||||
|
|
||||||
|
b.Property<string>("State");
|
||||||
|
|
||||||
|
b.Property<string>("Street");
|
||||||
|
|
||||||
|
b.Property<string>("ZipCode");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("address","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "orderseq")
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<int?>("AddressId");
|
||||||
|
|
||||||
|
b.Property<int?>("BuyerId");
|
||||||
|
|
||||||
|
b.Property<string>("Description");
|
||||||
|
|
||||||
|
b.Property<DateTime>("OrderDate");
|
||||||
|
|
||||||
|
b.Property<int>("OrderStatusId");
|
||||||
|
|
||||||
|
b.Property<int?>("PaymentMethodId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AddressId");
|
||||||
|
|
||||||
|
b.HasIndex("BuyerId");
|
||||||
|
|
||||||
|
b.HasIndex("OrderStatusId");
|
||||||
|
|
||||||
|
b.HasIndex("PaymentMethodId");
|
||||||
|
|
||||||
|
b.ToTable("orders","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "orderitemseq")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<decimal>("Discount");
|
||||||
|
|
||||||
|
b.Property<int>("OrderId");
|
||||||
|
|
||||||
|
b.Property<string>("PictureUrl");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId");
|
||||||
|
|
||||||
|
b.Property<string>("ProductName")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<decimal>("UnitPrice");
|
||||||
|
|
||||||
|
b.Property<int>("Units");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OrderId");
|
||||||
|
|
||||||
|
b.ToTable("orderItems","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasDefaultValue(1);
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(200);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("orderstatus","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency.ClientRequest", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("requests","ordering");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
|
||||||
|
.WithMany("PaymentMethods")
|
||||||
|
.HasForeignKey("BuyerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", "CardType")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CardTypeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AddressId");
|
||||||
|
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("BuyerId");
|
||||||
|
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", "OrderStatus")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OrderStatusId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("PaymentMethodId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
|
||||||
|
.WithMany("OrderItems")
|
||||||
|
.HasForeignKey("OrderId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Ordering.API.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddOrderDescription : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Description",
|
||||||
|
schema: "ordering",
|
||||||
|
table: "orders",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Description",
|
||||||
|
schema: "ordering",
|
||||||
|
table: "orders");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -121,6 +121,8 @@ namespace Ordering.API.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BuyerId");
|
b.Property<int?>("BuyerId");
|
||||||
|
|
||||||
|
b.Property<string>("Description");
|
||||||
|
|
||||||
b.Property<DateTime>("OrderDate");
|
b.Property<DateTime>("OrderDate");
|
||||||
|
|
||||||
b.Property<int>("OrderStatusId");
|
b.Property<int>("OrderStatusId");
|
||||||
@ -183,7 +185,7 @@ namespace Ordering.API.Migrations
|
|||||||
b.ToTable("orderstatus","ordering");
|
b.ToTable("orderstatus","ordering");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.ClientRequest", b =>
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency.ClientRequest", b =>
|
||||||
{
|
{
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using MediatR;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
|
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
|
||||||
using Ordering.Domain.Events;
|
using Ordering.Domain.Events;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -23,6 +21,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
public OrderStatus OrderStatus { get; private set; }
|
public OrderStatus OrderStatus { get; private set; }
|
||||||
private int _orderStatusId;
|
private int _orderStatusId;
|
||||||
|
|
||||||
|
private string _description;
|
||||||
|
|
||||||
// DDD Patterns comment
|
// DDD Patterns comment
|
||||||
// Using a private collection field, better for DDD Aggregate's encapsulation
|
// Using a private collection field, better for DDD Aggregate's encapsulation
|
||||||
@ -99,17 +98,25 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
_orderStatusId = id;
|
_orderStatusId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetOrderStockConfirmed(bool confirmed)
|
public void SetOrderStockConfirmed(IEnumerable<int> orderStockNotConfirmedItems = null)
|
||||||
{
|
{
|
||||||
if(confirmed)
|
if(orderStockNotConfirmedItems is null)
|
||||||
{
|
{
|
||||||
OrderStatus = OrderStatus.StockValidated;
|
OrderStatus = OrderStatus.StockValidated;
|
||||||
AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.StockValidated));
|
_description = "All the items were confirmed with available stock.";
|
||||||
|
//AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.StockValidated));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var itemsStockNotConfirmedProductNames = OrderItems
|
||||||
|
.Where(c => orderStockNotConfirmedItems.Contains(c.ProductId))
|
||||||
|
.Select(c => c.GetOrderItemProductName());
|
||||||
|
|
||||||
|
var itemsStockNotConfirmedDescription = string.Join(", ", itemsStockNotConfirmedProductNames);
|
||||||
|
|
||||||
OrderStatus = OrderStatus.Cancelled;
|
OrderStatus = OrderStatus.Cancelled;
|
||||||
AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.Cancelled));
|
_description = $"The product items don't have stock: ({itemsStockNotConfirmedDescription}).";
|
||||||
|
//AddDomainEvent(new OrderStockMethodVerifiedDomainEvent(Id, OrderStatus.Cancelled));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,3 +131,4 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
return _units;
|
return _units;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetOrderItemProductName() => _productName;
|
||||||
|
|
||||||
public void SetNewDiscount(decimal discount)
|
public void SetNewDiscount(decimal discount)
|
||||||
{
|
{
|
||||||
if (discount < 0)
|
if (discount < 0)
|
||||||
|
@ -156,6 +156,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
|||||||
orderConfiguration.Property<int?>("BuyerId").IsRequired(false);
|
orderConfiguration.Property<int?>("BuyerId").IsRequired(false);
|
||||||
orderConfiguration.Property<int>("OrderStatusId").IsRequired();
|
orderConfiguration.Property<int>("OrderStatusId").IsRequired();
|
||||||
orderConfiguration.Property<int?>("PaymentMethodId").IsRequired(false);
|
orderConfiguration.Property<int?>("PaymentMethodId").IsRequired(false);
|
||||||
|
orderConfiguration.Property<string>("Description").IsRequired(false);
|
||||||
|
|
||||||
var navigation = orderConfiguration.Metadata.FindNavigation(nameof(Order.OrderItems));
|
var navigation = orderConfiguration.Metadata.FindNavigation(nameof(Order.OrderItems));
|
||||||
// DDD Patterns comment:
|
// DDD Patterns comment:
|
||||||
|
@ -80,8 +80,6 @@ namespace SagaManager
|
|||||||
var container = new ContainerBuilder();
|
var container = new ContainerBuilder();
|
||||||
container.Populate(services);
|
container.Populate(services);
|
||||||
return new AutofacServiceProvider(container.Build());
|
return new AutofacServiceProvider(container.Build());
|
||||||
|
|
||||||
return services.BuildServiceProvider();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Configure(ILoggerFactory loggerFactory)
|
public static void Configure(ILoggerFactory loggerFactory)
|
||||||
|
@ -19,6 +19,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewModels
|
|||||||
|
|
||||||
public decimal Total {get;set;}
|
public decimal Total {get;set;}
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string City { get; set; }
|
public string City { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
|
@ -22,7 +22,17 @@
|
|||||||
<section class="esh-orders_detail-item col-xs-3">@Model.OrderNumber</section>
|
<section class="esh-orders_detail-item col-xs-3">@Model.OrderNumber</section>
|
||||||
<section class="esh-orders_detail-item col-xs-3">@Model.Date</section>
|
<section class="esh-orders_detail-item col-xs-3">@Model.Date</section>
|
||||||
<section class="esh-orders_detail-item col-xs-3">$@Model.Total</section>
|
<section class="esh-orders_detail-item col-xs-3">$@Model.Total</section>
|
||||||
<section class="esh-orders_detail-item col-xs-3">@Model.Status</section>
|
<section class="esh-orders_detail-title col-xs-3">@Model.Status</section>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="esh-orders_detail-section">
|
||||||
|
<article class="esh-orders_detail-titles row">
|
||||||
|
<section class="esh-orders_detail-title col-xs-12">Description</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="esh-orders_detail-items row">
|
||||||
|
<section class="esh-orders_detail-item col-xs-12">@Model.Description</section>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -18,6 +18,16 @@
|
|||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="esh-orders_detail-section">
|
||||||
|
<article class="esh-orders_detail-titles row">
|
||||||
|
<section class="esh-orders_detail-title col-xs-12">Description</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="esh-orders_detail-items row">
|
||||||
|
<section class="esh-orders_detail-item col-xs-12">{{order.description}}</section>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="esh-orders_detail-section">
|
<section class="esh-orders_detail-section">
|
||||||
<article class="esh-orders_detail-titles row">
|
<article class="esh-orders_detail-titles row">
|
||||||
<section class="esh-orders_detail-title col-xs-12">Shiping address</section>
|
<section class="esh-orders_detail-title col-xs-12">Shiping address</section>
|
||||||
|
@ -3,6 +3,7 @@ import {IOrderItem} from './orderItem.model';
|
|||||||
export interface IOrderDetail {
|
export interface IOrderDetail {
|
||||||
ordernumber: string;
|
ordernumber: string;
|
||||||
status: string;
|
status: string;
|
||||||
|
description: string;
|
||||||
street: string;
|
street: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
city: number;
|
city: number;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user