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))); }
//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); }
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); }
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>() })); }
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); }
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); }
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); }
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); }
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); }
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); }
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);
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); }
public async Task <MakePaymentCommandResponse> MakePayment([FromBody] MakePaymentCommand makePaymentCommand) { var result = await mediator.Send(makePaymentCommand); return(result); }
public bool RequestFunds(MakePaymentCommand request) { return(_fakeBankClientRepository.RequestFunds(request)); }