LocalGovIMS_localgov-ims/src/BusinessLogic/Validators/BasketValidator.cs
using BusinessLogic.Classes.Result;
using BusinessLogic.Interfaces.Result;
using BusinessLogic.Interfaces.Security;
using BusinessLogic.Interfaces.Validators;
using BusinessLogic.Models.Payments;
using log4net;
using System;
using System.Linq;

namespace BusinessLogic.Validators
{
    public class BasketValidator : IBasketValidator
    {
        private readonly ILog _logger;
        private readonly IPaymentValidationHandler _paymentValidationHandler;
        private readonly ISecurityContext _securityContext;

        private const string DefaultErrorMessage = "There is an error with the basket";

        public BasketValidator(ILog logger
            , IPaymentValidationHandler paymentValidationHandler
            , ISecurityContext securityContext)
        {
            _logger = logger;
            _paymentValidationHandler = paymentValidationHandler;
            _securityContext = securityContext;
        }

        public IResult Validate(Basket basket)
        {
            try
            {
                var validateItemsAreUniqueResult = ValidateItemsAreUnique(basket);
                if (!validateItemsAreUniqueResult.Success) return validateItemsAreUniqueResult;

                var validateItemsResult = ValidateItems(basket);
                if (!validateItemsResult.Success) return validateItemsResult;

                return new Result();
            }
            catch (Exception e)
            {
                _logger.Error(null, e);
                return new Result(DefaultErrorMessage);
            }
        }

        private IResult ValidateItemsAreUnique(Basket basket)
        {
            try
            {
                var repeatingItems = basket.Items.GroupBy(x => x.AccountReference)
                    .Where(grp => grp.Count() > 1)
                    .Select(grp => grp.Key);

                if (repeatingItems != null && repeatingItems.Any() && !_securityContext.IsInRole(BusinessLogic.Security.Role.Finance) && !_securityContext.IsInRole(BusinessLogic.Security.Role.ChequeProcess))
                {
                    return new Result("Duplicate account references detected");
                }

                return new Result();

            }
            catch (Exception e)
            {
                _logger.Error(null, e);
                return new Result(DefaultErrorMessage);
            }
        }

        private IResult ValidateItems(Basket basket)
        {
            try
            {
                var validationResult = new Result();

                foreach (var item in basket.Items)
                {
                    var result = _paymentValidationHandler.Validate(new Payment.PaymentValidationArgs()
                    {
                        Reference = item.AccountReference,
                        FundCode = item.FundCode,
                        Amount = item.Amount
                    });

                    if (!result.Success)
                    {
                        validationResult.AddError(result.Error);
                    }

                    if (item.Amount != decimal.Round(item.Amount, 2))
                    {
                        _logger.WarnFormat("An invalid payment amount has been discovered: {0}", item.Amount);
                        validationResult.AddError("A payment amount is invalid");
                    }
                }

                return validationResult;
            }
            catch (Exception e)
            {
                _logger.Error(null, e);
                return new Result(DefaultErrorMessage);
            }
        }
    }
}