Newer
Older
Warehouse / src / Application / Transactions / CreateTransaction / CreateTransactionCommandValidator.cs
@Derek Comartin Derek Comartin on 22 Aug 2023 2 KB Init
using MyWarehouse.Application.Common.Dependencies.DataAccess.Repositories;

namespace MyWarehouse.Application.Transactions.CreateTransaction;

public class CreateTransactionCommandValidator : AbstractValidator<CreateTransactionCommand>
{
    private readonly IProductRepository _productRepository;

    public CreateTransactionCommandValidator(IProductRepository productRepository)
    {
        _productRepository = productRepository;

        RuleFor(x => x.TransactionLines)
            .NotEmpty()
            .DependentRules(() => {

                RuleForEach(x => x.TransactionLines)
                    .Must(l => l.ProductQuantity > 0)
                    .WithMessage("Product quantity at line {CollectionIndex} must be larger than 0");

                RuleFor(x => x.TransactionLines)
                    .Must(x => x.GroupBy(x => x.ProductId).Any(g => g.Count() == 1))
                    .WithMessage("Can't have more than one transaction lines for the same product.");

                RuleFor(x => x.TransactionLines)
                    .MustAsync(HaveSufficientStock)
                    .WithMessage("Cannot record a sales transaction of quantity {RequestedQty} for product '{ProductName}', because current stock is {ProductStock}.");
            });
    }

    private async Task<bool> HaveSufficientStock(CreateTransactionCommand c, CreateTransactionCommand.TransactionLine[] lines, ValidationContext<CreateTransactionCommand> ctx, CancellationToken _)
    {
        if (c.TransactionType == Domain.TransactionType.Procurement)
        {
            return true;
        }

        var requestedProducts = await _productRepository.GetFiltered(
            x => lines.Select(l => l.ProductId).Contains(x.Id));

        foreach (var line in lines)
        {
            var product = requestedProducts.Where(p => p.Id == line.ProductId).Single();

            if (product.NumberInStock < line.ProductQuantity)
            {
                ctx.MessageFormatter.AppendArgument("ProductName", product.Name);
                ctx.MessageFormatter.AppendArgument("ProductStock", product.NumberInStock);
                ctx.MessageFormatter.AppendArgument("RequestedQty", line.ProductQuantity);
                return false;
            }
        }

        return true;
    }
}