public async Task ShouldMapBankTransactionDetailsOnPayment()
        {
            var mockBankSimChargeCard = new Mock <IChargeCardAdapter>();
            var mockRepo            = new Mock <IPaymentRepository>();
            var mockMerchantQueries = new Mock <IQueryMerchants>();
            var mockNotifyMerchantPaymentSucceeded = new Mock <INotifyMerchantPaymentSucceeded>();

            var merchant = new Merchant {
                AccountNumber = "888888"
            };
            var chargeResponse = new FinaliseTransactionResponse {
                BankSimTransactionId = Guid.NewGuid().ToString(), Success = true
            };

            mockMerchantQueries.Setup(x => x.GetById(It.IsAny <string>())).ReturnsAsync(merchant);
            mockBankSimChargeCard.Setup(x => x.Charge(It.IsAny <FinaliseTransactionRequest>())).ReturnsAsync(chargeResponse);

            var commandHander = new PaymentsCommandHandler(mockRepo.Object, mockMerchantQueries.Object, mockBankSimChargeCard.Object, mockNotifyMerchantPaymentSucceeded.Object);

            var command = new MakePaymentCommand {
                InvoiceId = Guid.NewGuid().ToString(), RecipientMerchantId = Guid.NewGuid().ToString(), SenderCardNumber = "4444444444444444", SenderCvv = "111", PaymentId = Guid.NewGuid().ToString(), Amount = 100
            };

            mockBankSimChargeCard.Setup(x => x.Charge(It.IsAny <FinaliseTransactionRequest>())).ReturnsAsync(chargeResponse);

            await commandHander.Handle(command);

            mockRepo.Verify(x => x.Add(It.Is <Payment>(payment => payment.BankSimTransactionId == chargeResponse.BankSimTransactionId)));
        }
        public async Task MakePaymentCallsChargeCardOnBankApi()
        {
            var bankSimChargeCard = new Mock <IChargeCardAdapter>();
            var mockRepo          = new Mock <IPaymentRepository>();
            var merchantQueries   = new Mock <IQueryMerchants>();
            var mockNotifyMerchantPaymentSucceeded = new Mock <INotifyMerchantPaymentSucceeded>();

            var merchant = new Merchant {
                AccountNumber = "888888"
            };

            merchantQueries.Setup(x => x.GetById(It.IsAny <string>())).ReturnsAsync(merchant);

            var commandHander = new PaymentsCommandHandler(mockRepo.Object, merchantQueries.Object, bankSimChargeCard.Object, mockNotifyMerchantPaymentSucceeded.Object);

            var command = new MakePaymentCommand {
                InvoiceId = Guid.NewGuid().ToString(), RecipientMerchantId = Guid.NewGuid().ToString(), SenderCardNumber = "4444444444444444", SenderCvv = "111", PaymentId = Guid.NewGuid().ToString(), Amount = 100
            };

            bankSimChargeCard.Setup(x => x.Charge(It.IsAny <FinaliseTransactionRequest>())).ReturnsAsync(new FinaliseTransactionResponse());

            await commandHander.Handle(command);

            bankSimChargeCard.Verify(x => x.Charge(It.Is <FinaliseTransactionRequest>(request =>
                                                                                      request.RecipientAccountNumber == merchant.AccountNumber &&
                                                                                      request.SenderCardNumber == command.SenderCardNumber)));
        }
示例#3
0
 //TODO refactor to take viewmodel and ids
 public void MakePayment(MakePaymentDto makePaymentDto)
 {
     using (var uow = UnitOfWork)
     {
         var command = new MakePaymentCommand(makePaymentDto.DateReceived, makePaymentDto.Amount, makePaymentDto.InventoryId);
         var handler = new MakePaymentCommandHandler(uow);
         var result  = handler.Handle(command);
     }
 }
        public IEnumerable <ValidationError> Validate(MakePaymentCommand request)
        {
            var list       = new List <ValidationError>();
            var cardNumber = request.BillingDetails.CardNumber.Replace(" ", string.Empty);

            var allowedPrefixes = new HashMap <string, List <int> >
            {
                { "visa", new List <int> {
                      4
                  } },
                { "amex", new List <int> {
                      34, 37
                  } },
                { "mastercard", new List <int> {
                      51, 52, 53, 54, 55
                  } }
            };

            int prefixDigits;

            switch (request.BillingDetails.CardType)
            {
            case "visa":
                prefixDigits = int.Parse(cardNumber.Substring(0, 1));
                allowedPrefixes.TryGetValue("visa", out var allowedValues);
                if (!allowedValues.Contains(prefixDigits))
                {
                    list.Add(new ValidationError("Validation Failure - Visa Card Number Prefix Incorrect"));
                }
                ;
                break;

            case "amex":
                prefixDigits = int.Parse(cardNumber.Substring(0, 2));
                allowedPrefixes.TryGetValue("amex", out allowedValues);
                if (!allowedValues.Contains(prefixDigits))
                {
                    list.Add(new ValidationError("Validation Failure - Amex Card Number Prefix Incorrect"));
                }
                ;
                break;

            case "mastercard":
                prefixDigits = int.Parse(cardNumber.Substring(0, 2));
                allowedPrefixes.TryGetValue("mastercard", out allowedValues);
                if (!allowedValues.Contains(prefixDigits))
                {
                    list.Add(new ValidationError("Validation Failure - Mastercard Card Number Prefix Incorrect"));
                }
                break;

            default:
                break;
            }

            return(list);
        }
示例#5
0
        public async Task MakePaymentRequestCallsThroughToMediator()
        {
            MakePaymentCommand command = new MakePaymentCommand();
            var mediator = new Mock <IMediator>();
            var sut      = new PaymentsController(mediator.Object);

            await sut.MakePayment(command);

            mediator.Verify(x => x.Send(It.Is <MakePaymentCommand>(y => y == command), It.IsAny <CancellationToken>()), Times.Once);
        }
示例#6
0
        public Task <PaymentResponse> ProcessPayment(MakePaymentCommand request)
        {
            // Set Bank Payment ID for event
            var id = new Guid().ToString();

            // Bank Validations
            var(isValid, validationErrors) = _fakeBankValidatorService.Validate(request);

            if (!isValid)
            {
                return(Task.FromResult(new PaymentResponse
                {
                    BankPaymentId = id,
                    Status = "failure",
                    ValidationErrors = validationErrors,
                    Reason = "Failed to validate payment details"
                }));
            }

            // Client Funds Verification
            isValid = _fakeBankClientService.RequestFunds(request);

            if (!isValid)
            {
                return(Task.FromResult(new PaymentResponse
                {
                    BankPaymentId = id,
                    Status = "failure",
                    Reason = "Failed to verify client funds",
                    ValidationErrors = new List <ValidationError>()
                }));;
            }

            // Merchant Money Processing
            isValid = _fakeBankMerchantService.ProcessFundsTransfer(request);

            if (!isValid)
            {
                return(Task.FromResult(new PaymentResponse
                {
                    BankPaymentId = id,
                    Status = "failure",
                    Reason = "Failed to process funds with merchant",
                    ValidationErrors = new List <ValidationError>()
                }));
            }

            return(Task.FromResult(new PaymentResponse
            {
                BankPaymentId = id,
                Status = "success",
                ValidationErrors = new List <ValidationError>()
            }));
        }
示例#7
0
        public IEnumerable <ValidationError> Validate(MakePaymentCommand request)
        {
            var list       = new List <ValidationError>();
            var cardNumber = request.BillingDetails.CardNumber.Replace(" ", string.Empty);

            var allowedLengths = new HashMap <string, List <int> >
            {
                { "visa", new List <int> {
                      13, 16, 19
                  } },
                { "amex", new List <int> {
                      15
                  } },
                { "mastercard", new List <int> {
                      16
                  } }
            };

            switch (request.BillingDetails.CardType)
            {
            case "visa":
                allowedLengths.TryGetValue("visa", out var allowedLengthList);
                if (!allowedLengthList.Contains(cardNumber.Length))
                {
                    list.Add(new ValidationError(ValidationMessage));
                }
                ;
                break;

            case "amex":
                allowedLengths.TryGetValue("amex", out allowedLengthList);
                if (!allowedLengthList.Contains(cardNumber.Length))
                {
                    list.Add(new ValidationError(ValidationMessage));
                }
                ;
                break;

            case "mastercard":
                allowedLengths.TryGetValue("mastercard", out allowedLengthList);
                if (!allowedLengthList.Contains(cardNumber.Length))
                {
                    list.Add(new ValidationError(ValidationMessage));
                }
                ;
                break;

            default:
                break;
            }

            return(list);
        }
        public void PassValidObject()
        {
            MakePaymentCommand command = new MakePaymentCommand
            {
                AuthenticatedUserId = Guid.NewGuid(),
                OrderId             = Guid.NewGuid()
            };
            MakePaymentCommandValidator testSubject = new MakePaymentCommandValidator();

            ValidationResult result = testSubject.Validate(command);

            Assert.True(result.IsValid);
        }
        public void FailOnMissingOrderId()
        {
            MakePaymentCommand command = new MakePaymentCommand
            {
                AuthenticatedUserId = Guid.NewGuid(),
                OrderId             = Guid.Empty
            };
            MakePaymentCommandValidator testSubject = new MakePaymentCommandValidator();

            ValidationResult result = testSubject.Validate(command);

            Assert.False(result.IsValid);
            Assert.Equal("OrderId", result.Errors.Single().PropertyName);
        }
示例#10
0
 private Payment MapToPayment(MakePaymentCommand command, Merchant recipient)
 {
     return(new Payment
     {
         PaymentId = Guid.NewGuid().ToString(),
         OrderId = command.OrderId,
         InvoiceId = command.InvoiceId,
         RecipientMerchantId = recipient.MerchantId,
         SenderCardNumber = command.SenderCardNumber,
         Amount = command.Amount,
         CurrencyCode = command.CurrencyCode,
         Status = PaymentStatus.Pending
     });
 }
        public async Task MakeValidPaymentCreatesPayment()
        {
            //Arrange:
            string bankSimTransactionId = Guid.NewGuid().ToString();

            _chargeCard.Setup(x => x.Charge(It.IsAny <FinaliseTransactionRequest>())).ReturnsAsync(new FinaliseTransactionResponse {
                BankSimTransactionId = bankSimTransactionId, Success = true
            });

            var maskedCardNumber   = "############4141";
            var makePaymentCommand = new MakePaymentCommand()
            {
                Amount              = 1000,
                CurrencyCode        = "GBP",
                SenderCardNumber    = "4141414141414141",
                SenderCvv           = "111",
                RecipientMerchantId = "TEST",
                InvoiceId           = Guid.NewGuid().ToString()
            };

            string paymentId = string.Empty;

            using (var scope = _privateServiceProvider.CreateScope())
            {
                var scopedServices    = scope.ServiceProvider;
                var paymentRepository = scopedServices.GetRequiredService <IPaymentRepository>();
                var queryMerchants    = scopedServices.GetRequiredService <CheckItOut.Payments.Domain.Queries.IQueryMerchants>();

                //Act:
                var paymentsCommandHandler = new PaymentsCommandHandler(paymentRepository, queryMerchants, _chargeCard.Object, new Mock <Domain.MerchantContracts.INotifyMerchantPaymentSucceeded>().Object);
                paymentId = await paymentsCommandHandler.Handle(makePaymentCommand);
            }

            //Assert:
            Payment payment = null;

            using (var scope = _privateServiceProvider.CreateScope())
            {
                var scopedServices    = scope.ServiceProvider;
                var paymentRepository = scopedServices.GetRequiredService <IPaymentRepository>();
                payment = await paymentRepository.GetById(paymentId);
            }
            Assert.Equal(makePaymentCommand.InvoiceId, payment.InvoiceId);
            Assert.Equal(payment.SenderCardNumber, maskedCardNumber);
            Assert.Equal(makePaymentCommand.Amount, payment.Amount);
            Assert.Equal(payment.BankSimTransactionId, bankSimTransactionId);
            Assert.Equal(payment.Status, PaymentStatus.Succeeded);
        }
示例#12
0
        public IEnumerable <ValidationError> FakeValidatior(MakePaymentCommand request)
        {
            // Create list for validation errors
            var list = new List <ValidationError>();

            // Pick 50/50 probability of getting an error
            var prob = new Random().Next(50) <= 25;

            // Add validation errors based on probability result
            if (prob)
            {
                list.Add(new ValidationError("Fake validation error"));
            }

            return(list);
        }
示例#13
0
 private FinaliseTransactionRequest MapToChargeRequest(MakePaymentCommand command, Merchant recipient)
 {
     return(new FinaliseTransactionRequest
     {
         InvoiceId = command.InvoiceId,
         RecipientAccountNumber = recipient.AccountNumber,
         RecipientSortCode = recipient.SortCode,
         SenderCardNumber = command.SenderCardNumber,
         SenderCvv = command.SenderCvv,
         SenderCardExpiryMonth = command.SenderCardExpiryMonth,
         SenderCardExpiryYear = command.SenderCardExpiryYear,
         RecipientFullName = recipient.FullName,
         SenderFullName = command.SenderFullName,
         Amount = command.Amount,
         CurrencyCode = command.CurrencyCode,
     });
 }
        private static (MakePaymentCommandDto, MakePaymentCommand) CreateFakeMakePaymentCommandAndDto()
        {
            var merchantPaymentId = "15359b7d-4e92-4a02-b303-f7529277fe05";
            var billingDetails    = new BillingDetails
            {
                Name           = "Test User",
                CardType       = "visa",
                CardNumber     = "4000100020003000",
                ExpiryMonth    = 12,
                ExpiryYear     = 2022,
                Cvv            = "155",
                BillingAddress = new BillingAddress()
                {
                    Title     = "Mr",
                    FirstName = "Test",
                    LastName  = "User",
                    Country   = "United Kingdom",
                    Address1  = "Test Address Line 1",
                    Address2  = "Test Address Line 2",
                    Postcode  = "ABC DEF"
                }
            };
            var currency = "GBP";
            var amount   = 100;

            var makePaymentCommandDto = new MakePaymentCommandDto
            {
                MerchantPaymentId = merchantPaymentId,
                BillingDetails    = billingDetails,
                Currency          = currency,
                Amount            = amount
            };

            var makePaymentCommand = new MakePaymentCommand
            {
                MerchantPaymentId = merchantPaymentId,
                BillingDetails    = billingDetails,
                Currency          = currency,
                Amount            = amount
            };

            return(makePaymentCommandDto, makePaymentCommand);
        }
示例#15
0
        public (bool, List <ValidationError>) Validate(MakePaymentCommand request)
        {
            var validationErrors = new List <ValidationError>();

            // Fake validators for the bank
            for (int i = 0; i < 5; i++)
            {
                var validatorErrors = FakeValidatior(request);

                if (validationErrors.Any())
                {
                    validationErrors.AddRange(validatorErrors);
                }
            }

            var isValid = !validationErrors.Any();

            return(isValid, validationErrors);
        }
示例#16
0
    public async Task Handle(PaymentCreatedEvent paymentCreatedEvent
                             , CancellationToken cancellationToken)
    {
        var payment = await _unitOfWork.Payments
                      .GetById(paymentCreatedEvent.PaymentId, cancellationToken);

        var customer = await _unitOfWork.Customers
                       .GetById(payment.CustomerId, cancellationToken);

        var order = await _unitOfWork.Orders
                    .GetById(payment.OrderId, cancellationToken);

        if (payment == null)
        {
            throw new ApplicationDataException("Payment not found.");
        }

        if (customer == null)
        {
            throw new ApplicationDataException("Customer not found.");
        }

        if (order == null)
        {
            throw new ApplicationDataException("order not found.");
        }

        // Changing order status
        _orderStatusWorkflow.CalculateOrderStatus(order, payment);
        await _unitOfWork.CommitAsync(cancellationToken);

        // Attempting to pay
        MakePaymentCommand command = new MakePaymentCommand(paymentCreatedEvent.PaymentId.Value);
        await _mediator.Send(command, cancellationToken);

        // Broadcasting order update
        await _orderStatusBroadcaster.BroadcastOrderStatus(
            customer.Id,
            order.Id,
            order.Status
            );
    }
        ////move to factory
        private static MakePaymentCommand MakeCommand(MakeGuestToMerchantPaymentRequest request)
        {
            var paymentId = Guid.NewGuid().ToString();

            var command = new MakePaymentCommand
            {
                PaymentId             = paymentId,
                InvoiceId             = request.InvoiceId,
                OrderId               = request.OrderId,
                Amount                = request.Amount,
                CurrencyCode          = request.CurrencyCode,
                RecipientMerchantId   = request.RecipientMerchantId,
                SenderCardNumber      = request.SenderCardNumber,
                SenderCvv             = request.SenderCvv,
                SenderCardExpiryMonth = request.SenderCardExpiryMonth,
                SenderCardExpiryYear  = request.SenderCardExpiryYear,
                UserId                = request.UserId
            };

            return(command);
        }
示例#18
0
        public async Task <string> Handle(MakePaymentCommand command)
        {
            var duplicatePaymentAttempt = _paymentRepository.GetByInvoiceId(command.InvoiceId).Result;

            if (duplicatePaymentAttempt != null && !string.IsNullOrWhiteSpace(duplicatePaymentAttempt.InvoiceId))
            {
                throw new Exception("Duplicate Payment Attempt, PaymentId with InvoiceId: " + command.InvoiceId + " already exists");
            }

            //Prepair ChargeRequest with Sender And Merchant Details
            var recipient     = _merchantQueries.GetById(command.RecipientMerchantId).Result;
            var chargeRequest = MapToChargeRequest(command, recipient);

            //Save Payment Request
            var payment = MapToPayment(command, recipient);

            _paymentRepository.Add(payment).Wait();
            _paymentRepository.Save().Wait();

            //ToDo: Implement Retries and Auth to Endpoint
            //MakePayment
            var chargeResponse = await _chargeCard.Charge(chargeRequest);

            if (chargeResponse.Success)
            {
                payment.Succeed(chargeResponse.BankSimTransactionId);
                _paymentRepository.Save().Wait();
                //ToDo: await _notifyMerchantPaymentSucceeded.Notify(command.InvoiceId, payment.PaymentId, recipient.MerchantId);
                //ToDo: await _notifyCustomerByEmailPaymentSucceeded.Notify(command.SenderEmail, command.InvoiceId, payment.PaymentId, recipient.MerchantId);
            }
            else
            {
                payment.Fail("return a reason from bank");
                _paymentRepository.Save().Wait();
            }

            //update paymentRequest.Status

            return(payment.PaymentId);
        }
 public async Task <IActionResult> Put([FromRoute] MakePaymentCommand command) => await ExecuteCommand(command);
示例#20
0
        public (bool, List <ValidationError>) Validate(IEnumerable <IPaymentValidator> paymentValidators, MakePaymentCommand request)
        {
            if (paymentValidators.Any())
            {
                var responses        = paymentValidators.Select(v => v.Validate(request));
                var isValid          = responses.All(a => !a.Any());
                var validationErrors = !isValid?responses.SelectMany(r => r.Where(a => a != null)).ToList() : null;

                return(isValid, validationErrors);
            }

            throw new PaymentValidatorsNotImplementedException("Payment validators must be implemented");
        }
 public bool ProcessFundsTransfer(MakePaymentCommand request)
 {
     // TODO - Need to fake repository request for processing funds to merchant
     return(true);
 }
        public bool RequestFunds(MakePaymentCommand request)
        {
            var random = new Random();

            return(random.Next(100) <= 50);
        }
示例#23
0
        public async Task <MakePaymentCommandResponse> MakePayment([FromBody] MakePaymentCommand makePaymentCommand)
        {
            var result = await mediator.Send(makePaymentCommand);

            return(result);
        }
示例#24
0
 public bool RequestFunds(MakePaymentCommand request)
 {
     return(_fakeBankClientRepository.RequestFunds(request));
 }