public When_A_Valid_Payment_Requested_For_A_Account()
        {
            _accountDataStore = new Mock <IAccountDataStore>();

            _account = new TestAccountBuilder()
                       .WithAccountNumber("Acct123456")
                       .WithAllowedPaymentSchemes(AllowedPaymentSchemes.FasterPayments)
                       .WithBalance(500m)
                       .WithStatus(AccountStatus.Live)
                       .Build();

            _accountDataStore.Setup(x => x.GetAccount(accountNumber)).Returns(_account);
            _paymentTypeRule = new Mock <IPaymentTypeRule>();


            var paymentRule = new Dictionary <PaymentScheme, Func <IPaymentSchemeRules> >()
            {
                { PaymentScheme.Bacs, () => new BacsPaymentSchemeRule() },
                { PaymentScheme.Chaps, () => new ChapsPaymentSchemeRule() },
                { PaymentScheme.FasterPayments, () => new FasterPaymentSchemeRule() }
            };

            _paymentScheme = PaymentScheme.FasterPayments;
            _paymentTypeRule.Setup(x => x.GetPaymentRule(_paymentScheme)).Returns(paymentRule[_paymentScheme]);
            _paymentService = new PaymentService(_accountDataStore.Object, _paymentTypeRule.Object);
        }
Example #2
0
        public void MakePaymentRequestWithInvalidPayementScheme()
        {
            Dictionary <String, Object> debitorAccount  = (Dictionary <String, Object>)context["DebitorAccount"];
            Dictionary <String, Object> creditorAccount = (Dictionary <String, Object>)context["CreditorAccount"];
            DateTime paymentDate = DateTime.Now;

            string creditorAccountNumber = creditorAccount["AccountNumber"].ToString();
            string debitorAccountNumber  = debitorAccount["AccountNumber"].ToString();

            decimal debitAmount = (decimal)context["DebitAmount"];

            // Object status = Enum.Parse(typeof(AccountStatus), debitorAccount["AccountStatus"].ToString());
            PaymentScheme debitorPaymentScheme = (PaymentScheme)Enum.Parse(typeof(PaymentScheme), debitorAccount["PaymentScheme"].ToString());

            //Get invalid payment scheme
            var values = Enum.GetValues(typeof(PaymentScheme));

            foreach (var val in values)
            {
                if (!(val.ToString().Equals(debitorAccount["PaymentScheme"].ToString())))
                {
                    debitorPaymentScheme = (PaymentScheme)Enum.Parse(typeof(PaymentScheme), val.ToString());
                    break;
                }
            }

            MakePaymentRequest request = new MakePaymentRequest(creditorAccountNumber,
                                                                debitorAccountNumber, debitAmount, paymentDate, debitorPaymentScheme);

            PaymentService    paymentService = new PaymentService();
            MakePaymentResult result         = paymentService.MakePayment(request);

            context["MakePaymentResult"] = result;
        }
        public void GetPaymentSchemeValidator_ShouldReturnCorrectValidator(PaymentScheme paymentSceme)
        {
            _paymentSchemeValidatorServiceInTest = new PaymentSchemeValidatorService(new [] { _bacPaymentRequestValidatorMock.Object, _chapsPaymentRequestValidatorMock.Object, _fasterPaymentsPaymentRequestValidatorMock.Object });

            var validator = _paymentSchemeValidatorServiceInTest.GetPaymentSchemeValidator(paymentSceme);

            Assert.That(validator, Is.Not.Null);
        }
Example #4
0
        public IPaymentType Get(PaymentScheme paymentScheme)
        {
            IPaymentType paymentType = this._paymentTypes.FirstOrDefault(p => p.Type == paymentScheme);

            Guard.AgainstNull(paymentType, $"PaymentType for Scheme {paymentScheme.ToString()} is not registered.");

            return(paymentType);
        }
Example #5
0
        public IPaymentSchemeRules GetPaymentRule(PaymentScheme paymentScheme)
        {
            var paymentRule = new Dictionary <PaymentScheme, Func <IPaymentSchemeRules> >()
            {
                { PaymentScheme.Bacs, () => new BacsPaymentSchemeRule() },
                { PaymentScheme.Chaps, () => new ChapsPaymentSchemeRule() },
                { PaymentScheme.FasterPayments, () => new FasterPaymentSchemeRule() }
            };

            return(paymentRule[paymentScheme]());
        }
Example #6
0
        public bool CheckAccountStatus(Account account, PaymentScheme paymentScheme, decimal requestedAmount)
        {
            if (account == null)
            {
                return(false);
            }

            var paymentValidator = paymentValidatorFactory.GetPaymentValidator(paymentScheme);

            return(paymentValidator.IsAccountAllowedToMakePayment(account, requestedAmount));
        }
        public void FailedPayment(PaymentScheme paymentScheme, PaymentScheme allowedPaymentSchemes, decimal balance, AccountStatus accountStatus)
        {
            var payment = new TestPaymentService();

            payment.Account.AllowedPaymentSchemes = allowedPaymentSchemes;
            payment.Account.Balance = balance;
            payment.Account.Status  = accountStatus;
            var request = CreateStandardRequest(paymentScheme);

            Assert.IsFalse(payment.MakePayment(request).Success);
        }
 /// <summary>
 /// Creates a payment request for 50 pounds to credit account 111111 from 222222 now,
 /// using the specified payment scheme.
 /// </summary>
 private MakePaymentRequest CreateStandardRequest(PaymentScheme paymentScheme)
 {
     return(new MakePaymentRequest
     {
         Amount = 50.0M,
         CreditorAccountNumber = "11111111",
         DebtorAccountNumber = "22222222",
         PaymentDate = DateTime.Now,
         PaymentScheme = paymentScheme
     });
 }
Example #9
0
 public MakePaymentRequest(string creditorAccountNumber,
                           string debitorAccountNumber,
                           decimal amount,
                           DateTime paymentDate,
                           PaymentScheme paymentScheme)
 {
     CreditorAccountNumber = creditorAccountNumber;
     DebtorAccountNumber   = debitorAccountNumber;
     Amount        = amount;
     PaymentDate   = paymentDate;
     PaymentScheme = paymentScheme;
 }
Example #10
0
        public void Credit(decimal amount, PaymentScheme scheme)
        {
            ValidatePaymentType(scheme);

            //same comment as above applies
            if (this.Status != AccountStatus.Live && this.Status != AccountStatus.InboundPaymentsOnly)
            {
                throw new InvalidOperationException("Incorrect account status.");
            }

            this.Balance += amount;
        }
Example #11
0
        public void GivenIHavePaymentRequestDetails(PaymentScheme paymentScheme, string creditorAccountNumber, string debtorAccountNumber, decimal amount, DateTime paymentDate)
        {
            var request = new MakePaymentRequest()
            {
                PaymentScheme         = paymentScheme,
                CreditorAccountNumber = creditorAccountNumber,
                DebtorAccountNumber   = debtorAccountNumber,
                Amount      = amount,
                PaymentDate = paymentDate
            };

            ScenarioContext.Current["Request"] = request;
        }
        public void ReturnsCorrectValidator(PaymentScheme scheme, Type expectedType)
        {
            // Arrange
            var factory = new ValidatorFactory();
            var request = new MakePaymentRequest {
                PaymentScheme = scheme
            };

            // Act
            var validator = factory.BuildValidator(request);

            // Assert
            Assert.AreEqual(expectedType, validator.GetType());
        }
Example #13
0
        public virtual IPaymentSchemeValidator GetPaymentSchemeValidator(PaymentScheme paymentScheme)
        {
            switch (paymentScheme)
            {
            case PaymentScheme.Bacs:
                return(new BacsPaymentSchemeValidator());

            case PaymentScheme.FasterPayments:
                return(new FasterPaymentSchemeValidator());

            default:
                return(new ChapsPaymentSchemeValidator());
            }
        }
Example #14
0
 protected void ValidatePaymentType(PaymentScheme scheme)
 {
     //To my knowledge this rule applies to all types of payments. Therefore it belongs here because in the spirit of
     //DDD and DRY it's part of the validation of the Account domain entity.
     //Another approach is to implement all the rules in a separate service e.g. IPaymentValidationService that is injected in Payment Service.
     //I didn't do that because logically these checks are common for all payment schemes. In a real world scenario it
     //would be clear from the bussiness requirements that it's beneficial to decouple the validation logic to separate
     //classes per payment scheme.
     if (!this.AllowedPaymentSchemes.HasFlag(scheme))
     {
         //normally there would be a custom exception like DomainArgumentException etc
         throw new InvalidOperationException($"The account does not support {scheme.ToString()} payments.");
     }
 }
Example #15
0
        public IEnumerable <IPaymentRule> GetRules(PaymentScheme paymentScheme)
        {
            yield return(new AccountExistsRule());

            yield return(new PaymentSchemeRule(GetAllowedPaymentSchemes(paymentScheme)));

            if (paymentScheme is PaymentScheme.FasterPayments)
            {
                yield return(new AccountHasFundsRule());
            }

            if (paymentScheme is PaymentScheme.Chaps)
            {
                yield return(new AccountIsLiveRule());
            }
        }
Example #16
0
        public void MakePaymentRequest()
        {
            Dictionary <String, Object> debitorAccount  = (Dictionary <String, Object>)context["DebitorAccount"];
            Dictionary <String, Object> creditorAccount = (Dictionary <String, Object>)context["CreditorAccount"];
            DateTime paymentDate           = DateTime.Now;
            string   creditorAccountNumber = creditorAccount["AccountNumber"].ToString();
            string   debitorAccountNumber  = debitorAccount["AccountNumber"].ToString();
            decimal  debitAmount           = (decimal)context["DebitAmount"];

            PaymentScheme      paymentScheme  = (PaymentScheme)Enum.Parse(typeof(PaymentScheme), debitorAccount["PaymentScheme"].ToString());
            MakePaymentRequest request        = new MakePaymentRequest(creditorAccountNumber, debitorAccountNumber, debitAmount, paymentDate, paymentScheme);
            PaymentService     paymentService = new PaymentService();
            MakePaymentResult  result         = paymentService.MakePayment(request);

            context["MakePaymentResult"] = result;
        }
Example #17
0
        public void Debit(decimal amount, PaymentScheme scheme)
        {
            ValidatePaymentType(scheme);

            //same comment as above applies
            if (this.Status != AccountStatus.Live)
            {
                throw new InvalidOperationException("Incorrect account status.");
            }
            else if (this.Balance < amount)
            {
                throw new InvalidOperationException("Insufficient funds.");
            }

            this.Balance -= amount;
        }
        public IPaymentRule Create(PaymentScheme scheme)
        {
            switch (scheme)
            {
            case PaymentScheme.Bacs:
                return(new BacsPaymentRule(_accountSuitableRule));

            case PaymentScheme.FasterPayments:
                return(new FasterPaymentsPaymentRule(_accountSuitableRule));

            case PaymentScheme.Chaps:
                return(new ChapsPaymentRule(_accountSuitableRule));

            default:
                throw new InvalidEnumArgumentException("Payment scheme not recognised");
            }
        }
Example #19
0
        public IPaymentSchemeValidator Create(PaymentScheme paymentScheme, Account account, MakePaymentRequest request)
        {
            switch (paymentScheme)
            {
            case PaymentScheme.Bacs:
                return(new BacsPaymentSchemeValidator(account));

            case PaymentScheme.Chaps:
                return(new ChapsPaymentSchemeValidator(account));

            case PaymentScheme.FasterPayments:
                return(new FasterPaymentsPaymentSchemeValidator(account, request));

            default:
                throw new PaymentSchemeNotFoundException($"The payment scheme '{paymentScheme}' was not found.");
            }
        }
Example #20
0
        public static IPaymentSchemeValidator GetValidator(PaymentScheme paymentScheme)
        {
            switch (paymentScheme)
            {
            case PaymentScheme.Bacs:
                return(new BacsPaymentSchemeValidator());

            case PaymentScheme.FasterPayments:
                return(new FasterPaymentSchemeValidator());

            case PaymentScheme.Chaps:
                return(new ChapsPaymentSchemeValidator());

            default:
                return(new NullPaymentSchemeValidator());
            }
        }
Example #21
0
        public IPaymentScheme GetPaymentScheme(PaymentScheme paymentScheme)
        {
            switch (paymentScheme)
            {
            case PaymentScheme.FasterPayments:
                return(new FasterPaymentScheme());

            case PaymentScheme.Bacs:
                return(new BacsPaymentScheme());

            case PaymentScheme.Chaps:
                return(new ChapsPaymentScheme());

            default:
                return(null);
            }
        }
        public IValidator GetValidator(PaymentScheme scheme)
        {
            switch (scheme)
            {
            case PaymentScheme.FasterPayments:
                return(new FasterPaymentValidator());

            case PaymentScheme.Bacs:
                return(new BacsPaymentValidator());

            case PaymentScheme.Chaps:
                return(new ChapsPaymentValidator());

            default:
                throw new ArgumentOutOfRangeException(nameof(scheme));
            }
        }
Example #23
0
        public PaymentSchemeValidator GetPaymentSchemeValidator(PaymentScheme allowedPaymentSchemes)
        {
            switch (allowedPaymentSchemes)
            {
            case PaymentScheme.Bacs:

                return(new BacsPaymentValidator());

            case PaymentScheme.FasterPayments:

                return(new FasterPaymentsValidator());

            case PaymentScheme.Chaps:

                return(new ChapsPaymentValidator());
            }

            return(null);
        }
        public static bool IsAllowedPaymentScheme(this Account account, PaymentScheme paymentScheme)
        {
            if (account == null)
            {
                return(false);
            }

            if ((int)paymentScheme != (int)account.AllowedPaymentSchemes)
            {
                return(false);
            }
            if ((int)paymentScheme != (int)AllowedPaymentSchemes.Chaps && account.Status != AccountStatus.Live)
            {
                return(false);
            }

            //Меня смутило то, что в AllowedPaymentScheme сдвинуты номера. Я решил оставить как есть.

            return(true);
        }
Example #25
0
        public void WhenRequestIsValid_AndAccountExists_AndHasMatchingAllowedPaymentScheme_UpdatesBalanceInDatastore(
            PaymentScheme requestedScheme, AllowedPaymentSchemes allowedScheme)
        {
            var storedAccount = ExistingStoredAccount(balance: 1000m, allowedScheme: allowedScheme);

            _mockDataStore.Setup(dataStore => dataStore.GetAccount(ExistingDebtorAccountNumber))
            .Returns((true, storedAccount));

            var makePaymentRequest = new MakePaymentRequest(
                "creditorAccount",
                ExistingDebtorAccountNumber,
                100.0m, DateTime.Now,
                requestedScheme);

            _ = _paymentService.MakePayment(makePaymentRequest);

            _mockDataStore.Verify(datastore => datastore.UpdateAccount(
                                      It.Is <Account>(account => account.AccountNumber.Equals(ExistingDebtorAccountNumber) &&
                                                      account.Balance.Equals(900m)
                                                      )));
        }
Example #26
0
        public static bool ExecutePayment(PaymentScheme scheme, Account account, MakePaymentRequest request)
        {
            if (account != null)
            {
                switch (scheme)
                {
                case PaymentScheme.Bacs:
                    if (!account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.Bacs))
                    {
                        return(false);
                    }
                    break;

                case PaymentScheme.FasterPayments:
                    if (!account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.FasterPayments) || account.Balance < request.Amount)
                    {
                        return(false);
                    }
                    break;

                case PaymentScheme.Chaps:
                    if (!account.AllowedPaymentSchemes.HasFlag(AllowedPaymentSchemes.Chaps))
                    {
                        return(false);
                    }
                    else if (account.Status != AccountStatus.Live)
                    {
                        return(false);
                    }
                    break;

                default:
                    return(false);
                }
            }
            return(false);
        }
Example #27
0
        public bool IsMovementAuthorized(Account originatorAccount, PaymentScheme scheme, decimal ammount)
        {
            // Avoid nesting for compiled code optimization
            if (originatorAccount == null ||
                !originatorAccount.AllowedPaymentSchemes.HasFlag((AllowedPaymentSchemes)scheme))
            {
                return(false);
            }

            var result = false;

            switch (scheme)
            {
            case PaymentScheme.FasterPayments:
                result = originatorAccount.HasValidBalance(ammount);
                break;

            case PaymentScheme.Bacs:
                result = true;
                break;

            case PaymentScheme.Chaps:
                result = originatorAccount.Status == AccountStatus.Live;
                break;

            default:
                // Although we just return false (for security reasons), we still keep track of the exception for later analysis
                // in a live system we might also include additional information required for future investigation taking sensitive data masking
                // needs into account
                // I also chose to maintain the default handler to deal with
                Logger.LogException(new ArgumentOutOfRangeException(nameof(scheme), scheme, null));
                break;
            }

            return(result);
        }
Example #28
0
        public MakePaymentResult CheckPaymentEligible(PaymentScheme paymentScheme, Account account, decimal amount)
        {
            var result = new MakePaymentResult();
            var paymentSchemeValidator = _resolvePaymentSchemeValidator.GetPaymentSchemeValidator(paymentScheme);

            switch (paymentScheme)
            {
            case PaymentScheme.Bacs:
                result.Success = (account != null) && paymentSchemeValidator.IsPaymentSchemeAllowedOnAccount(account);
                break;

            case PaymentScheme.FasterPayments:
                result.Success = (account != null) && paymentSchemeValidator.IsPaymentSchemeAllowedOnAccount(account) &&
                                 _accountService.HasSuffientBalance(account, amount);
                break;

            case PaymentScheme.Chaps:
                result.Success = (account != null) && paymentSchemeValidator.IsPaymentSchemeAllowedOnAccount(account) &&
                                 _accountService.CheckAccountStatus(account, AccountStatus.Live);
                break;
            }

            return(result);
        }
        public void MakePayment_PaymentValidationServiceIsCalledWithCorrectPaymentScheme(PaymentScheme paymentScheme)
        {
            _makePaymentRequest.PaymentScheme = paymentScheme;

            _paymentServiceInTest.MakePayment(_makePaymentRequest);

            _paymentSchemeValidatorServiceMock.Verify(validatorService => validatorService.GetPaymentSchemeValidator(paymentScheme), Times.Once);
        }
Example #30
0
 public IPaymentValidator CreateValidator(PaymentScheme paymentScheme)
 {
     return(_paymentValidators[paymentScheme]);
 }
 private void detach_PaymentSchemes(PaymentScheme entity)
 {
     this.SendPropertyChanging("PaymentSchemes");
     entity.Organisation = null;
 }
 private void attach_PaymentSchemes(PaymentScheme entity)
 {
     this.SendPropertyChanging("PaymentSchemes");
     entity.Person = this;
 }
 private void detach_PaymentSchemes(PaymentScheme entity)
 {
     this.SendPropertyChanging("PaymentSchemes");
     entity.RbOKPF = null;
 }