public async Task <PaymentRequestResult> InitiatePartnerPaymentAsync(IPaymentRequest paymentRequest) { #region Validation if (string.IsNullOrEmpty(paymentRequest.CustomerId)) { throw new ArgumentNullException(nameof(paymentRequest.CustomerId)); } if (string.IsNullOrEmpty(paymentRequest.PartnerId)) { throw new ArgumentNullException(nameof(paymentRequest.PartnerId)); } if (string.IsNullOrEmpty(paymentRequest.Currency)) { throw new ArgumentNullException(nameof(paymentRequest.Currency)); } var isPartnerIdValidGuid = Guid.TryParse(paymentRequest.PartnerId, out var partnerId); if (!isPartnerIdValidGuid) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.PartnerIdIsNotAValidGuid)); } var isCustomerIdValidGuid = Guid.TryParse(paymentRequest.CustomerId, out var customerGuid); if (!isCustomerIdValidGuid) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.CustomerIdIsNotAValidGuid)); } //We can have either amount in Tokens or in Fiat if (paymentRequest.FiatAmount != null && paymentRequest.TokensAmount != null) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.CannotPassBothFiatAndTokensAmount)); } //Fiat or Tokens Amount must be provided if (paymentRequest.FiatAmount == null && paymentRequest.TokensAmount == null) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.EitherFiatOrTokensAmountShouldBePassed)); } if (paymentRequest.TokensAmount != null && paymentRequest.TokensAmount <= 0) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.InvalidTokensAmount)); } if (paymentRequest.FiatAmount != null && paymentRequest.FiatAmount <= 0) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.InvalidFiatAmount)); } if (paymentRequest.TotalBillAmount <= 0) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.InvalidTotalBillAmount)); } var customerProfile = await _customerProfileClient.CustomerProfiles.GetByCustomerIdAsync(paymentRequest.CustomerId); if (customerProfile.ErrorCode == CustomerProfileErrorCodes.CustomerProfileDoesNotExist) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.CustomerDoesNotExist)); } var customerWalletStatus = await _walletManagementClient.Api.GetCustomerWalletBlockStateAsync(paymentRequest.CustomerId); if (customerWalletStatus.Status == CustomerWalletActivityStatus.Blocked) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.CustomerWalletBlocked)); } var partnerDetails = await _partnerManagementClient.Partners.GetByIdAsync(partnerId); if (partnerDetails == null) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.PartnerDoesNotExist)); } if (!string.IsNullOrEmpty(paymentRequest.LocationId)) { if (partnerDetails.Locations.All(x => x.Id.ToString() != paymentRequest.LocationId)) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.NoSuchLocationForThisPartner)); } } #endregion var paymentRequestId = Guid.NewGuid().ToString(); paymentRequest.PaymentRequestId = paymentRequestId; //Blockchain does not accept null if (paymentRequest.LocationId == null) { paymentRequest.LocationId = ""; } var convertOptimalByPartnerModel = new ConvertOptimalByPartnerRequest { CustomerId = customerGuid, PartnerId = partnerId, Amount = paymentRequest.TokensAmount ?? paymentRequest.FiatAmount.Value, FromCurrency = paymentRequest.TokensAmount.HasValue ? _tokenSymbol : paymentRequest.Currency, ToCurrency = paymentRequest.TokensAmount.HasValue ? paymentRequest.Currency : _tokenSymbol }; var convertOptimalByPartnerResponse = await _eligibilityEngineClient.ConversionRate.ConvertOptimalByPartnerAsync(convertOptimalByPartnerModel); if (convertOptimalByPartnerResponse.ErrorCode != EligibilityEngineErrors.None) { if (convertOptimalByPartnerResponse.ErrorCode == EligibilityEngineErrors.PartnerNotFound) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.PartnerDoesNotExist)); } if (convertOptimalByPartnerResponse.ErrorCode == EligibilityEngineErrors.ConversionRateNotFound) { return(PaymentRequestResult.Failed(PaymentRequestErrorCodes.InvalidTokensOrCurrencyRateInPartner)); } } paymentRequest.TokensToFiatConversionRate = convertOptimalByPartnerResponse.UsedRate; if (paymentRequest.FiatAmount == null) { paymentRequest.FiatAmount = (decimal)convertOptimalByPartnerResponse.Amount; } else { paymentRequest.TokensAmount = convertOptimalByPartnerResponse.Amount; } var now = DateTime.UtcNow; paymentRequest.CustomerActionExpirationTimestamp = paymentRequest.CustomerExpirationInSeconds.HasValue ? now.AddSeconds(paymentRequest.CustomerExpirationInSeconds.Value) : now.Add(_settingsService.GetRequestsExpirationPeriod()); await _paymentsRepository.AddAsync(paymentRequest); await _paymentRequestCreatedPublisher.PublishAsync(new PartnerPaymentRequestCreatedEvent { PaymentRequestId = paymentRequestId, CustomerId = paymentRequest.CustomerId, PartnerId = paymentRequest.PartnerId, Timestamp = DateTime.UtcNow }); return(PaymentRequestResult.Succeeded(PaymentRequestStatus.Created, paymentRequestId)); }