public async Task <ServiceObjectResult <ICollection <Transaction> > > GetAllTransactions(string userId)
        {
            //Check cache
            var cachedTransactions = await _userDataCachingService.RetrieveTransactions(userId);

            if (!cachedTransactions.Success)
            {
                return(ServiceObjectResult <ICollection <Transaction> > .Failed(null, cachedTransactions.Errors));
            }

            if (cachedTransactions.Result != null && cachedTransactions.Result.Any())
            {
                return(ServiceObjectResult <ICollection <Transaction> > .Succeeded(cachedTransactions.Result));
            }

            //Obtain all valid access contexts
            var accessContextResult = await ObtainValidAccountContexts(userId);

            if (!accessContextResult.Success)
            {
                return(ServiceObjectResult <ICollection <Transaction> > .Failed(null, accessContextResult.Errors));
            }

            var transactionsResult = await ObtainTransactionsForAccountContexts(accessContextResult.Result);

            if (!transactionsResult.Success)
            {
                return(ServiceObjectResult <ICollection <Transaction> > .Failed(null, transactionsResult.Errors));
            }

            await _userDataCachingService.CacheTransactions(userId, transactionsResult.Result, TimeSpan.FromMinutes(10));

            return(ServiceObjectResult <ICollection <Transaction> > .Succeeded(transactionsResult.Result));
        }
Beispiel #2
0
        public async Task <ServiceObjectResult <PaymentResult> > ExecutePayment(PaymentRequest paymentRequest)
        {
            var sendPaymentResponse = await _bankRequestClient.SendPayment(paymentRequest);

            if (!sendPaymentResponse.Success || sendPaymentResponse.Result?.PaymentIdentifier == null)
            {
                return(ServiceObjectResult <PaymentResult> .Failed(null, sendPaymentResponse.Errors ?? new List <string> {
                    ErrorCodeStrings.InternalError
                }));
            }

            if (!Enum.TryParse <PaymentStatus>(sendPaymentResponse.Result.Status, out var paymentStatus))
            {
                return(ServiceObjectResult <PaymentResult> .Failed(null, ErrorMessages.UnableToProcessPayment));
            }

            var paymentResult = new PaymentResult
            {
                PaymentIdentifier = sendPaymentResponse.Result.PaymentIdentifier,
                CardNumber        = paymentRequest.CardNumber,
                Amount            = paymentRequest.Amount,
                Status            = paymentStatus,
                Timestamp         = DateTime.UtcNow
            };

            return(ServiceObjectResult <PaymentResult> .Succeeded(paymentResult));
        }
Beispiel #3
0
        public async Task <ServiceObjectResult <ResponseEnvelope <PaymentResponse> > > ProcessPaymentRequest(PaymentRequest request)
        {
            var responseEnvelope = new ResponseEnvelope <PaymentResponse>();

            var validationResult = _requestValidator.ValidateRequest(request);

            if (!validationResult.Success)
            {
                responseEnvelope.ValidationErrors = validationResult.Result;
                return(ServiceObjectResult <ResponseEnvelope <PaymentResponse> >
                       .Failed(
                           responseEnvelope,
                           validationResult.Errors));
            }

            var paymentResult = await _paymentExecutionService.ExecutePayment(request);

            if (!paymentResult.Success)
            {
                return(ServiceObjectResult <ResponseEnvelope <PaymentResponse> > .Failed(null,
                                                                                         new List <string> {
                    ErrorCodeStrings.InternalError
                }));
            }

            await _repository.PutItemAsync(paymentResult.Result);

            responseEnvelope.ResponseValue = new PaymentResponse
            {
                PaymentIdentifier = paymentResult.Result.PaymentIdentifier,
                Status            = paymentResult.Result.Status.ToString()
            };

            return(ServiceObjectResult <ResponseEnvelope <PaymentResponse> > .Succeeded(responseEnvelope));
        }
        private async Task <ServiceObjectResult <ICollection <Transaction> > > ObtainTransactionsForAccountContexts(
            ICollection <AccountAccessContext> accessContexts)
        {
            var transactions = new List <Transaction>();

            foreach (var accessContext in accessContexts)
            {
                var accountLookupResult = await _accountService.GetAccountsInContext(accessContext);

                if (!accountLookupResult.Success)
                {
                    return(ServiceObjectResult <ICollection <Transaction> > .Failed(null, accountLookupResult.Errors));
                }

                foreach (var accountId in accountLookupResult.Result.Select(x => x.AccountId).Distinct())
                {
                    var transactionLookupResult =
                        await _requestExecutor.GetTransactions(accessContext.AccessToken, accountId);

                    if (!transactionLookupResult.Success)
                    {
                        return(ServiceObjectResult <ICollection <Transaction> > .Failed(null,
                                                                                        transactionLookupResult.Errors));
                    }

                    transactions.AddRange(transactionLookupResult.Result.Results);
                }
            }

            return(ServiceObjectResult <ICollection <Transaction> > .Succeeded(transactions));
        }
        private ServiceObjectResult <TReturnType> GenerateResponseForType <TReturnType>(string userId)
            where TReturnType : class
        {
            switch (userId)
            {
            case TestConstants.ValidUser:
                return(ServiceObjectResult <TReturnType> .Succeeded(null));

            case TestConstants.ErrorUser:
                return(ServiceObjectResult <TReturnType> .Failed(null, new List <string> {
                    ErrorCodeStrings.InternalError
                }));

            case TestConstants.BadRequestUser:
                return(ServiceObjectResult <TReturnType> .Failed(null, new List <string> {
                    ErrorCodeStrings.BadRequestError
                }));

            case TestConstants.NotFoundUser:
                return(ServiceObjectResult <TReturnType> .Failed(null, new List <string> {
                    ErrorCodeStrings.NotFoundError
                }));

            default:
                throw new NotImplementedException();
            }
        }
Beispiel #6
0
        public Task <ServiceObjectResult <ResponseEnvelope <PaymentResponse> > > ProcessPaymentRequest(PaymentRequest request)
        {
            switch (request.CardNumber)
            {
            case TestConstants.ErrorCardNumber:
                return(Task.FromResult(ServiceObjectResult <ResponseEnvelope <PaymentResponse> > .Failed(null,
                                                                                                         new List <string> {
                    ErrorCodeStrings.InternalError
                })));

            case TestConstants.BadRequestCardNumber:
                var validationErrors = new List <ValidationFieldError>
                {
                    new ValidationFieldError(nameof(request.CardNumber), ErrorMessages.Validation.FieldInvalidContent)
                };
                return(Task.FromResult(ServiceObjectResult <ResponseEnvelope <PaymentResponse> > .Failed(
                                           new ResponseEnvelope <PaymentResponse> {
                    ValidationErrors = validationErrors
                },
                                           new List <string> {
                    ErrorCodeStrings.BadRequestError
                })));

            case TestConstants.SuccessCardNumber:
                return(Task.FromResult(ServiceObjectResult <ResponseEnvelope <PaymentResponse> > .Succeeded(
                                           new ResponseEnvelope <PaymentResponse>
                {
                    ResponseValue = new PaymentResponse()
                })));

            default:
                throw new NotImplementedException();
            }
        }
        private async Task <ServiceObjectResult <ICollection <AccountAccessContext> > > ObtainValidAccountContexts(string userId)
        {
            //Refresh access on all users accounts where required
            var accessRefreshResult = await _authorizationService.AttemptRefreshAccountContexts(userId);

            if (!accessRefreshResult.Success)
            {
                return(ServiceObjectResult <ICollection <AccountAccessContext> > .Failed(null, accessRefreshResult.Errors));
            }

            //ObtainAccessContexts
            var accessContextResult = await _accessCachingService.RetrieveAccessContexts(userId, new List <Scope> {
                Scope.transactions, Scope.accounts
            });

            if (!accessContextResult.Success)
            {
                return(ServiceObjectResult <ICollection <AccountAccessContext> > .Failed(null, accessContextResult.Errors));
            }

            if (accessContextResult.Result == null)
            {
                return(ServiceObjectResult <ICollection <AccountAccessContext> > .Failed(null, new List <string> {
                    ErrorMessages.UserNotFound
                }));
            }

            return(ServiceObjectResult <ICollection <AccountAccessContext> > .Succeeded(accessContextResult.Result));
        }
        GetTransactionCategoryResponses(string userId, bool detailed = false)
        {
            //Check cache
            var cachedTransactions = await _userDataCachingService.RetrieveTransactions(userId);

            if (!cachedTransactions.Success)
            {
                return(ServiceObjectResult <TransactionCategoryResponse> .Failed(null, cachedTransactions.Errors));
            }

            if (cachedTransactions.Result != null && cachedTransactions.Result.Any())
            {
                return(ServiceObjectResult <TransactionCategoryResponse> .Succeeded(CreateCategoryResponse(cachedTransactions.Result, detailed)));
            }

            //Obtain all valid access contexts
            var accessContextResult = await ObtainValidAccountContexts(userId);

            if (!accessContextResult.Success)
            {
                return(ServiceObjectResult <TransactionCategoryResponse> .Failed(null, accessContextResult.Errors));
            }

            var transactionsResult = await ObtainTransactionsForAccountContexts(accessContextResult.Result);

            if (!transactionsResult.Success)
            {
                return(ServiceObjectResult <TransactionCategoryResponse> .Failed(null, transactionsResult.Errors));
            }

            await _userDataCachingService.CacheTransactions(userId, transactionsResult.Result, TimeSpan.FromMinutes(10));

            return(ServiceObjectResult <TransactionCategoryResponse> .Succeeded(CreateCategoryResponse(transactionsResult.Result, detailed)));
        }
        public async Task <ServiceObjectResult <TDataType> > GetItem(string partitionKey)
        {
            var result = await _dynamoDbContext.LoadAsync <TDataType>(partitionKey);

            return(result != null ?
                   ServiceObjectResult <TDataType> .Succeeded(result)
                : ServiceObjectResult <TDataType> .Failed(null, ErrorCodes.Status.NotFound));
        }
        public async Task <ServiceObjectResult <DeliveryRecord> > Update(DeliveryRecord delivery)
        {
            var result = await _repository.UpdateItem(delivery);

            return(!result.Success ?
                   ServiceObjectResult <DeliveryRecord> .Failed(null, result.Errors)
                : ServiceObjectResult <DeliveryRecord> .Succeeded(delivery));
        }
        public async Task <ServiceObjectResult <DeliveryRecord> > Select(string deliveryId)
        {
            var result = await _repository.GetItem(deliveryId);

            return(!result.Success ?
                   ServiceObjectResult <DeliveryRecord> .Failed(null, result.Errors)
                : ServiceObjectResult <DeliveryRecord> .Succeeded(result.Result));
        }
Beispiel #12
0
        public async void ExecutePayment_Should_Return_Failed_If_Client_Request_Fails()
        {
            _mockBankRequestClient.Setup(x => x.SendPayment(It.IsAny <PaymentRequest>()))
            .ReturnsAsync(ServiceObjectResult <BankPaymentResponse> .Failed(null, new List <string>()));

            var result = await _paymentExecutionService.ExecutePayment(new PaymentRequest());

            Assert.False(result.Success);
        }
        private void SetupPaymentExecutionService(string cardNumber, bool success, string resultReference = null)
        {
            var result = success
                ? ServiceObjectResult <PaymentResult> .Succeeded(new PaymentResult { PaymentIdentifier = resultReference })
                : ServiceObjectResult <PaymentResult> .Failed(null, "");

            _paymentExecutionService.Setup(x =>
                                           x.ExecutePayment(It.Is <PaymentRequest>(request => request.CardNumber == cardNumber)))
            .ReturnsAsync(result);
        }
        public async Task <ServiceObjectResult <DeliveryRecord> > Create(DeliveryRecord delivery)
        {
            delivery.DeliveryId = Guid.NewGuid().ToString();

            var saveResult = await _repository.PutItem(delivery);

            return(saveResult.Success ?
                   ServiceObjectResult <DeliveryRecord> .Succeeded(delivery)
                : ServiceObjectResult <DeliveryRecord> .Failed(null, saveResult.Errors));
        }
        private void SetupValidationService(string cardNumber, ICollection <ValidationFieldError> validationErrors)
        {
            var result = validationErrors.Any()
                ? ServiceObjectResult <ICollection <ValidationFieldError> > .Failed(validationErrors,
                                                                                    ErrorCodeStrings.BadRequestError)
                : ServiceObjectResult <ICollection <ValidationFieldError> > .Succeeded(validationErrors);

            _requestValidator.Setup(x =>
                                    x.ValidateRequest(It.Is <PaymentRequest>(request => request.CardNumber == cardNumber)))
            .Returns(result);
        }
        public DeliveryStateServiceTests()
        {
            _mockRepository = new Mock <IDynamoDbRepository <DeliveryRecord> >();
            var mockLogger = new Mock <ILogger <DeliveryStateService> >();

            _deliveryStateService = new DeliveryStateService(mockLogger.Object, _mockRepository.Object);

            _mockRepository.Setup(x => x.UpdateItem(It.IsAny <DeliveryRecord>()))
            .ReturnsAsync(ServiceResult.Succeeded);

            _mockRepository.Setup(x => x.GetItem(It.IsAny <string>()))
            .ReturnsAsync(ServiceObjectResult <DeliveryRecord> .Failed(null, ErrorCodes.Status.NotFound));
        }
        public async Task <ServiceObjectResult <ICollection <DeliveryRecord> > > Select(DeliveryState?state = null)
        {
            var result = state.HasValue ?
                         await _repository.GetItems(new List <QueryModel>
            {
                new QueryModel(nameof(DeliveryRecord.State), ScanOperator.Equal, state)
            })
                : await _repository.GetItems();

            return(result.Success ?
                   ServiceObjectResult <ICollection <DeliveryRecord> > .Succeeded(result.Result)
                : ServiceObjectResult <ICollection <DeliveryRecord> > .Failed(null, result.Errors));
        }
        public async Task <ServiceObjectResult <ICollection <TDataModel> > > QueryByPartitionAsync(string partitionKey)
        {
            var queryRequest = new QueryRequest(_configuration.TableName)
            {
                ExpressionAttributeNames = new Dictionary <string, string>
                {
                    { "#partition", _configuration.PartitionKey }
                },
                ExpressionAttributeValues = new Dictionary <string, AttributeValue>
                {
                    { ":partition", new AttributeValue(partitionKey) }
                },
                KeyConditionExpression = $"#partition = :partition"
            };

            bool operationComplete = false;

            var results = new List <Dictionary <string, AttributeValue> >();

            while (!operationComplete)
            {
                var queryResponse = await _dynamoDbClient.QueryAsync(queryRequest);

                if (queryResponse.HttpStatusCode != HttpStatusCode.OK)
                {
                    return(ServiceObjectResult <ICollection <TDataModel> > .Failed(null, $"An error occurred querying DynamoDb"));
                }

                results.AddRange(queryResponse.Items);

                if (queryResponse.LastEvaluatedKey.Any())
                {
                    queryRequest.ExclusiveStartKey = queryResponse.LastEvaluatedKey;
                }
                else
                {
                    operationComplete = true;
                }
            }

            var dataModels = new List <TDataModel>();

            foreach (var result in results)
            {
                var dataModel = new TDataModel();
                dataModel.FromAttributeMap(result);
                dataModels.Add(dataModel);
            }

            return(ServiceObjectResult <ICollection <TDataModel> > .Succeeded(dataModels));
        }
Beispiel #19
0
        public async void ExchangeCode_Should_Return_Failed_If_Call_Fails()
        {
            var myError = "Error";

            _mockRequestExecutor
            .Setup(x => x.ExchangeCode(It.IsAny <AccountAccessContext>()))
            .ReturnsAsync(ServiceObjectResult <AuthResponse> .Failed(null, new List <string> {
                myError
            }));

            var result = await _authorizationService.ExchangeCode(new AccountAccessContext());

            Assert.False(result.Success);
            Assert.Contains(myError, result.Errors);
        }
Beispiel #20
0
        public async void Delete_Should_Return_Errors_If_Select_Fails()
        {
            var error = "Error";

            var deliveryId = Guid.NewGuid().ToString();

            _mockRepository.Setup(x =>
                                  x.DeleteItem(deliveryId))
            .ReturnsAsync(ServiceObjectResult <DeliveryRecord> .Failed(null, error));


            var result = await _deliveryService.Delete(deliveryId);

            Assert.False(result.Success);
            Assert.Contains(error, result.Errors);
        }
Beispiel #21
0
        public async Task <ServiceObjectResult <ICollection <PaymentResult> > > QueryByPartitionAsync(string partitionKey)
        {
            switch (partitionKey)
            {
            case TestConstants.NotFoundPaymentIdentifier:
                return(ServiceObjectResult <ICollection <PaymentResult> > .Failed(null, ErrorCodeStrings.NotFoundError));

            default:
                return(ServiceObjectResult <ICollection <PaymentResult> > .Succeeded(new List <PaymentResult>
                {
                    new PaymentResult {
                        PaymentIdentifier = partitionKey
                    }
                }));
            }
        }
Beispiel #22
0
        public async Task <ServiceObjectResult <ICollection <Account> > > GetAccountsInContext(
            AccountAccessContext accessContext)
        {
            var accountsInContextResult = await _requestExecutor.GetAccounts(accessContext.AccessToken);

            if (!accountsInContextResult.Success || accountsInContextResult.Result.Status != "Succeeded")
            {
                return(ServiceObjectResult <ICollection <Account> > .Failed(null,
                                                                            accountsInContextResult.Errors ?? new List <string>
                {
                    "An error occurred fetching account information"
                }));
            }

            return(ServiceObjectResult <ICollection <Account> > .Succeeded(accountsInContextResult.Result.Results));
        }
        public async void GetAccountsInContext_Should_Return_Failed_If_Executor_Call_Fails()
        {
            var accessContext = new AccountAccessContext
            {
                AccessToken = "AccessToken"
            };

            _mockTrueLayerRequestExecutor.Setup(x => x.GetAccounts(accessContext.AccessToken))
            .ReturnsAsync(ServiceObjectResult <TrueLayerListResponse <Account> > .Failed(null, new List <string> {
                "Value"
            }));

            var result = await _accountService.GetAccountsInContext(accessContext);

            Assert.False(result.Success);
            _mockTrueLayerRequestExecutor.Verify(x => x.GetAccounts(accessContext.AccessToken), Times.Once);
        }
Beispiel #24
0
        public async void Process_Should_Not_Clear_User_Data_If_ExchangeCode_Fails()
        {
            var userId          = Guid.NewGuid().ToString();
            var code            = Guid.NewGuid().ToString();
            var callbackRequest = new CallbackRequest
            {
                Code  = code,
                Scope = $"{Scope.accounts.ToString()} {Scope.offline_access.ToString()}"
            };

            _mockAuthorizationService
            .Setup(x => x.ExchangeCode(It.Is <AccountAccessContext>(context => context.Code == code && context.UserId == userId)))
            .ReturnsAsync(ServiceObjectResult <AccountAccessContext> .Failed(null, new List <string>()));

            var result = await _callbackService.Process(userId, callbackRequest);

            Assert.False(result.Success);
            _mockAuthorizationService.Verify(x => x.ExchangeCode(It.Is <AccountAccessContext>(context => context.Code == code && context.UserId == userId)), Times.Once);
            _mockUserDataCachingService.Verify(x => x.ClearUserData(It.IsAny <string>()), Times.Never);
        }
Beispiel #25
0
        private ServiceObjectResult <TResponseType> CreateObjectResponseForRequest <TResponseType>(string deliveryId)
            where TResponseType : class, new()
        {
            switch (deliveryId)
            {
            case TestConstants.BadRequestValue:
                return(ServiceObjectResult <TResponseType> .Failed(null, ErrorCodes.Status.BadRequest));

            case TestConstants.InternalErrorValue:
                return(ServiceObjectResult <TResponseType> .Failed(null, ErrorCodes.Status.UnexpectedError));

            case TestConstants.NotFound:
                return(ServiceObjectResult <TResponseType> .Failed(null, ErrorCodes.Status.NotFound));

            case TestConstants.SuccessValue:
                return(ServiceObjectResult <TResponseType> .Succeeded(new TResponseType()));

            default:
                throw new NotImplementedException();
            }
        }
Beispiel #26
0
        public async Task <ServiceObjectResult <PaymentResult> > GetPaymentResult(string paymentIdentifier)
        {
            var paymentResults = await _repository.QueryByPartitionAsync(paymentIdentifier);

            if (!paymentResults.Success)
            {
                return(ServiceObjectResult <PaymentResult> .Failed(null, ErrorCodeStrings.InternalError));
            }

            if (!paymentResults.Result.Any())
            {
                return(ServiceObjectResult <PaymentResult> .Failed(null, ErrorCodeStrings.NotFoundError));
            }

            if (paymentResults.Result.Count != 1)
            {
                _logger.LogError($"Query for PaymentResult with identifier {paymentIdentifier} returned multiple results");
                return(ServiceObjectResult <PaymentResult> .Failed(null, ErrorCodeStrings.InternalError));
            }

            return(ServiceObjectResult <PaymentResult> .Succeeded(paymentResults.Result.Single()));
        }
        public async Task <ServiceObjectResult <AccountAccessContext> > ExchangeCode(AccountAccessContext accessContext)
        {
            var exchangeCodeResult = await _trueLayerDataRequestExecutor.ExchangeCode(accessContext);

            if (!exchangeCodeResult.Success)
            {
                return(ServiceObjectResult <AccountAccessContext> .Failed(accessContext, exchangeCodeResult.Errors));
            }

            accessContext.AccessToken       = exchangeCodeResult.Result.AccessToken;
            accessContext.RefreshToken      = exchangeCodeResult.Result.RefreshToken;
            accessContext.AccessTokenExpiry = DateTime.UtcNow.AddSeconds(exchangeCodeResult.Result.ExpiresIn);

            var saveContextResult = await ObtainMetadataAndUpdateCache(accessContext);

            if (!saveContextResult.Success)
            {
                return(ServiceObjectResult <AccountAccessContext> .Failed(null, saveContextResult.Errors));
            }

            return(ServiceObjectResult <AccountAccessContext> .Succeeded(accessContext));
        }
Beispiel #28
0
        public async Task <ServiceObjectResult <BankPaymentResponse> > SendPayment(PaymentRequest paymentRequest)
        {
            //TODO Mock the bank response based on user input (cardnumber)

            switch (paymentRequest.CardNumber)
            {
            case "1111111111111111":
                return(ServiceObjectResult <BankPaymentResponse> .Failed(null, "Unable to process payment"));

            case "2222222222222222":
                return(ServiceObjectResult <BankPaymentResponse> .Succeeded(new BankPaymentResponse
                {
                    Status = PaymentStatus.Failed.ToString()
                }));

            default:
                return(ServiceObjectResult <BankPaymentResponse> .Succeeded(new BankPaymentResponse
                {
                    PaymentIdentifier = Guid.NewGuid().ToString(),
                    Status = PaymentStatus.Complete.ToString()
                }));
            }
        }
Beispiel #29
0
        private void SetupExchangeCodeRequest(bool succeeded = true, string accessToken = null, string refreshToken = null)
        {
            var authResponse = new AuthResponse
            {
                AccessToken  = accessToken ?? Guid.NewGuid().ToString(),
                ExpiresIn    = 10,
                RefreshToken = refreshToken ?? Guid.NewGuid().ToString()
            };

            _mockRequestExecutor
            .Setup(x => x.ExchangeCode(It.IsAny <AccountAccessContext>()))
            .ReturnsAsync(succeeded ? ServiceObjectResult <AuthResponse> .Succeeded(authResponse) : ServiceObjectResult <AuthResponse> .Failed(null, new List <string> {
                "Value"
            }));
        }
        public ServiceObjectResult <ICollection <ValidationFieldError> > ValidateRequest(PaymentRequest request)
        {
            var validationErrors = new List <ValidationFieldError>();

            if (request.CardNumber == null)
            {
                validationErrors.Add(new ValidationFieldError(nameof(request.CardNumber), ErrorMessages.Validation.FieldMissing));
            }
            else
            {
                if (request.CardNumber?.Length != 16)
                {
                    validationErrors.Add(new ValidationFieldError(nameof(request.CardNumber), ErrorMessages.Validation.FieldInvalidLength));
                }

                if (!request.CardNumber.All(char.IsDigit))
                {
                    validationErrors.Add(new ValidationFieldError(nameof(request.CardNumber), ErrorMessages.Validation.FieldInvalidContent));
                }
            }

            if (request.Cvv == null)
            {
                validationErrors.Add(new ValidationFieldError(nameof(request.Cvv), ErrorMessages.Validation.FieldMissing));
            }
            else
            {
                if (request.Cvv.Length != 3)
                {
                    validationErrors.Add(new ValidationFieldError(nameof(request.Cvv), ErrorMessages.Validation.FieldInvalidLength));
                }

                if (!request.Cvv.All(char.IsDigit))
                {
                    validationErrors.Add(new ValidationFieldError(nameof(request.Cvv), ErrorMessages.Validation.FieldInvalidContent));
                }
            }

            if (request.Currency == null)
            {
                validationErrors.Add(new ValidationFieldError(nameof(request.Currency), ErrorMessages.Validation.FieldMissing));
            }
            else
            {
                if (!Enum.TryParse <Currency>(request.Currency, out _))
                {
                    validationErrors.Add(new ValidationFieldError(nameof(request.Currency), ErrorMessages.Validation.FieldInvalidContent));
                }
            }

            if (request.Amount == default || request.Amount <= 0)
            {
                validationErrors.Add(new ValidationFieldError(nameof(request.Amount), ErrorMessages.Validation.FieldInvalidContent));
            }


            if (request.ExpiryDate == null)
            {
                validationErrors.Add(new ValidationFieldError(nameof(request.ExpiryDate), ErrorMessages.Validation.FieldMissing));
            }
            else
            {
                if (!DateTime.TryParseExact(request.ExpiryDate, "MM/yy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var expiryDate))
                {
                    validationErrors.Add(new ValidationFieldError(nameof(request.ExpiryDate), ErrorMessages.Validation.FieldInvalidContent));
                }

                if (expiryDate < DateTime.UtcNow)
                {
                    validationErrors.Add(new ValidationFieldError(nameof(request.ExpiryDate), ErrorMessages.Validation.FieldInvalidContent));
                }
            }

            if (validationErrors.Any())
            {
                return(ServiceObjectResult <ICollection <ValidationFieldError> > .Failed(validationErrors, new List <string> {
                    ErrorCodeStrings.BadRequestError
                }));
            }

            return(ServiceObjectResult <ICollection <ValidationFieldError> > .Succeeded(validationErrors));
        }