private void AddPaymentMethods(StoreData store, StoreBlob storeBlob, StoreViewModel vm) { var excludeFilters = storeBlob.GetExcludedPaymentMethods(); var derivationByCryptoCode = store .GetSupportedPaymentMethods(_NetworkProvider) .OfType <DerivationSchemeSettings>() .ToDictionary(c => c.Network.CryptoCode.ToUpperInvariant()); var lightningByCryptoCode = store .GetSupportedPaymentMethods(_NetworkProvider) .OfType <LightningSupportedPaymentMethod>() .ToDictionary(c => c.CryptoCode.ToUpperInvariant()); foreach (var paymentMethodId in _paymentMethodHandlerDictionary.Distinct().SelectMany(handler => handler.GetSupportedPaymentMethods())) { switch (paymentMethodId.PaymentType) { case BitcoinPaymentType _: var strategy = derivationByCryptoCode.TryGet(paymentMethodId.CryptoCode); var network = _NetworkProvider.GetNetwork <BTCPayNetwork>(paymentMethodId.CryptoCode); var value = strategy?.ToPrettyString() ?? string.Empty; vm.DerivationSchemes.Add(new StoreViewModel.DerivationScheme() { Crypto = paymentMethodId.CryptoCode, WalletSupported = network.WalletSupported, Value = value, WalletId = new WalletId(store.Id, paymentMethodId.CryptoCode), Enabled = !excludeFilters.Match(paymentMethodId) && strategy != null, #if ALTCOINS Collapsed = network is ElementsBTCPayNetwork elementsBTCPayNetwork && elementsBTCPayNetwork.NetworkCryptoCode != elementsBTCPayNetwork.CryptoCode && string.IsNullOrEmpty(value) #endif }); break;
internal async Task <DataWrapper <InvoiceResponse> > CreateInvoiceCore(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List <string>?additionalTags = null, CancellationToken cancellationToken = default) { var entity = await CreateInvoiceCoreRaw(invoice, store, serverUrl, additionalTags, cancellationToken); var resp = entity.EntityToDTO(); return(new DataWrapper <InvoiceResponse>(resp) { Facade = "pos/invoice" }); }
public PaymentMethodOptionViewModel.Format[] GetEnabledPaymentMethodChoices(StoreData storeData) { var enabled = storeData.GetEnabledPaymentIds(_NetworkProvider); return(enabled .Select(o => new PaymentMethodOptionViewModel.Format() { Name = o.ToPrettyString(), Value = o.ToString(), PaymentId = o }).ToArray()); }
PaymentMethodOptionViewModel.Format?GetDefaultPaymentMethodChoice(StoreData storeData) { var enabled = storeData.GetEnabledPaymentIds(_NetworkProvider); var defaultPaymentId = storeData.GetDefaultPaymentId(); var defaultChoice = defaultPaymentId is not null?defaultPaymentId.FindNearest(enabled) : null; if (defaultChoice is null) { defaultChoice = enabled.FirstOrDefault(e => e.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode && e.PaymentType == PaymentTypes.BTCLike) ?? enabled.FirstOrDefault(e => e.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode && e.PaymentType == PaymentTypes.LightningLike) ?? enabled.FirstOrDefault(); } var choices = GetEnabledPaymentMethodChoices(storeData); return(defaultChoice is null ? null : choices.FirstOrDefault(c => defaultChoice.ToString().Equals(c.Value, StringComparison.OrdinalIgnoreCase))); }
public async Task <IViewComponentResult> InvokeAsync(StoreData store) { await using var ctx = _dbContextFactory.CreateContext(); var payoutsCount = await ctx.Payouts .Where(p => p.PullPaymentData.StoreId == store.Id && !p.PullPaymentData.Archived && p.State == PayoutState.AwaitingApproval) .CountAsync(); var refundsCount = await ctx.Invoices .Where(i => i.StoreData.Id == store.Id && !i.Archived && i.CurrentRefundId != null) .CountAsync(); var walletId = new WalletId(store.Id, CryptoCode); var derivation = store.GetDerivationSchemeSettings(_networkProvider, walletId.CryptoCode); var transactionsCount = 0; if (derivation != null) { var network = derivation.Network; var wallet = _walletProvider.GetWallet(network); var allTransactions = await wallet.FetchTransactions(derivation.AccountDerivation); var afterDate = DateTimeOffset.UtcNow - TimeSpan.FromDays(TransactionDays); transactionsCount = allTransactions.UnconfirmedTransactions.Transactions .Concat(allTransactions.ConfirmedTransactions.Transactions) .Count(t => t.Timestamp > afterDate); } var vm = new StoreNumbersViewModel { Store = store, WalletId = walletId, PayoutsPending = payoutsCount, Transactions = transactionsCount, TransactionDays = TransactionDays, RefundsIssued = refundsCount }; return(View(vm)); }
public static IEnumerable <LightningNetworkPaymentMethodData> GetLightningPaymentMethods(StoreData store, BTCPayNetworkProvider networkProvider, bool?enabled) { var blob = store.GetStoreBlob(); var excludedPaymentMethods = blob.GetExcludedPaymentMethods(); return(store.GetSupportedPaymentMethods(networkProvider) .Where((method) => method.PaymentId.PaymentType == PaymentTypes.LightningLike) .OfType <LightningSupportedPaymentMethod>() .Select(paymentMethod => new LightningNetworkPaymentMethodData( paymentMethod.PaymentId.CryptoCode, paymentMethod.GetExternalLightningUrl()?.ToString() ?? paymentMethod.GetDisplayableConnectionString(), !excludedPaymentMethods.Match(paymentMethod.PaymentId), paymentMethod.PaymentId.ToStringNormalized(), paymentMethod.DisableBOLT11PaymentOption ) ) .Where((result) => enabled is null || enabled == result.Enabled) .ToList()); }
public override async Task <IPaymentMethodDetails> CreatePaymentMethodDetails( InvoiceLogs logs, DerivationSchemeSettings supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store, BTCPayNetwork network, object preparePaymentObject) { if (preparePaymentObject is null) { return(new BitcoinLikeOnChainPaymentMethod() { Activated = false }); } if (!_ExplorerProvider.IsAvailable(network)) { throw new PaymentMethodUnavailableException($"Full node not available"); } var prepare = (Prepare)preparePaymentObject; var onchainMethod = new BitcoinLikeOnChainPaymentMethod(); var blob = store.GetStoreBlob(); onchainMethod.Activated = true; // TODO: this needs to be refactored to move this logic into BitcoinLikeOnChainPaymentMethod // This is likely a constructor code onchainMethod.NetworkFeeMode = blob.NetworkFeeMode; onchainMethod.FeeRate = await prepare.GetFeeRate; switch (onchainMethod.NetworkFeeMode) { case NetworkFeeMode.Always: onchainMethod.NetworkFeeRate = (await prepare.GetNetworkFeeRate); onchainMethod.NextNetworkFee = onchainMethod.NetworkFeeRate.GetFee(100); // assume price for 100 bytes break; case NetworkFeeMode.Never: onchainMethod.NetworkFeeRate = FeeRate.Zero; onchainMethod.NextNetworkFee = Money.Zero; break; case NetworkFeeMode.MultiplePaymentsOnly: onchainMethod.NetworkFeeRate = (await prepare.GetNetworkFeeRate); onchainMethod.NextNetworkFee = Money.Zero; break; } var reserved = await prepare.ReserveAddress; onchainMethod.DepositAddress = reserved.Address.ToString(); onchainMethod.KeyPath = reserved.KeyPath; onchainMethod.PayjoinEnabled = blob.PayJoinEnabled && supportedPaymentMethod .AccountDerivation.ScriptPubKeyType() != ScriptPubKeyType.Legacy && network.SupportPayJoin; if (onchainMethod.PayjoinEnabled) { var prefix = $"{supportedPaymentMethod.PaymentId.ToPrettyString()}:"; var nodeSupport = _dashboard?.Get(network.CryptoCode)?.Status?.BitcoinStatus?.Capabilities ?.CanSupportTransactionCheck is true; onchainMethod.PayjoinEnabled &= supportedPaymentMethod.IsHotWallet && nodeSupport; if (!supportedPaymentMethod.IsHotWallet) { logs.Write($"{prefix} Payjoin should have been enabled, but your store is not a hotwallet", InvoiceEventData.EventSeverity.Warning); } if (!nodeSupport) { logs.Write($"{prefix} Payjoin should have been enabled, but your version of NBXplorer or full node does not support it.", InvoiceEventData.EventSeverity.Warning); } if (onchainMethod.PayjoinEnabled) { logs.Write($"{prefix} Payjoin is enabled for this invoice.", InvoiceEventData.EventSeverity.Info); } } return(onchainMethod); }
internal async Task <InvoiceEntity> CreateInvoiceCoreRaw(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List <string>?additionalTags = null, CancellationToken cancellationToken = default) { var storeBlob = store.GetStoreBlob(); var entity = _InvoiceRepository.CreateNewInvoice(); entity.ExpirationTime = invoice.ExpirationTime is DateTimeOffset v ? v : entity.InvoiceTime + storeBlob.InvoiceExpiration; entity.MonitoringExpiration = entity.ExpirationTime + storeBlob.MonitoringExpiration; if (entity.ExpirationTime - TimeSpan.FromSeconds(30.0) < entity.InvoiceTime) { throw new BitpayHttpException(400, "The expirationTime is set too soon"); } entity.Metadata.OrderId = invoice.OrderId; entity.Metadata.PosData = invoice.PosData; entity.ServerUrl = serverUrl; entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications; entity.ExtendedNotifications = invoice.ExtendedNotifications; entity.NotificationURLTemplate = invoice.NotificationURL; entity.NotificationEmail = invoice.NotificationEmail; if (additionalTags != null) { entity.InternalTags.AddRange(additionalTags); } FillBuyerInfo(invoice, entity); var taxIncluded = invoice.TaxIncluded.HasValue ? invoice.TaxIncluded.Value : 0m; var price = invoice.Price; entity.Metadata.ItemCode = invoice.ItemCode; entity.Metadata.ItemDesc = invoice.ItemDesc; entity.Metadata.Physical = invoice.Physical; entity.Metadata.TaxIncluded = invoice.TaxIncluded; entity.Currency = invoice.Currency; if (price is decimal vv) { entity.Price = vv; entity.Type = InvoiceType.Standard; } else { entity.Price = 0m; entity.Type = InvoiceType.TopUp; } entity.RedirectURLTemplate = invoice.RedirectURL ?? store.StoreWebsite; entity.RedirectAutomatically = invoice.RedirectAutomatically.GetValueOrDefault(storeBlob.RedirectAutomatically); entity.RequiresRefundEmail = invoice.RequiresRefundEmail; entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy); IPaymentFilter?excludeFilter = null; if (invoice.PaymentCurrencies?.Any() is true) { invoice.SupportedTransactionCurrencies ??= new Dictionary <string, InvoiceSupportedTransactionCurrency>(); foreach (string paymentCurrency in invoice.PaymentCurrencies) { invoice.SupportedTransactionCurrencies.TryAdd(paymentCurrency, new InvoiceSupportedTransactionCurrency() { Enabled = true }); } } if (invoice.SupportedTransactionCurrencies != null && invoice.SupportedTransactionCurrencies.Count != 0) { var supportedTransactionCurrencies = invoice.SupportedTransactionCurrencies .Where(c => c.Value.Enabled) .Select(c => PaymentMethodId.TryParse(c.Key, out var p) ? p : null) .Where(c => c != null) .ToHashSet(); excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p)); } entity.PaymentTolerance = storeBlob.PaymentTolerance; entity.DefaultPaymentMethod = invoice.DefaultPaymentMethod; entity.RequiresRefundEmail = invoice.RequiresRefundEmail; return(await CreateInvoiceCoreRaw(entity, store, excludeFilter, null, cancellationToken)); }
public static void SetDefaultPaymentId(this StoreData storeData, PaymentMethodId defaultPaymentId) { storeData.DefaultCrypto = defaultPaymentId.ToString(); }
internal async Task <InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List <string>?additionalTags = null, CancellationToken cancellationToken = default) { var storeBlob = store.GetStoreBlob(); var entity = _InvoiceRepository.CreateNewInvoice(); entity.ServerUrl = serverUrl; entity.ExpirationTime = entity.InvoiceTime + (invoice.Checkout.Expiration ?? storeBlob.InvoiceExpiration); entity.MonitoringExpiration = entity.ExpirationTime + (invoice.Checkout.Monitoring ?? storeBlob.MonitoringExpiration); if (invoice.Metadata != null) { entity.Metadata = InvoiceMetadata.FromJObject(invoice.Metadata); } invoice.Checkout ??= new CreateInvoiceRequest.CheckoutOptions(); entity.Currency = invoice.Currency; if (invoice.Amount is decimal v) { entity.Price = v; entity.Type = InvoiceType.Standard; } else { entity.Price = 0.0m; entity.Type = InvoiceType.TopUp; } entity.SpeedPolicy = invoice.Checkout.SpeedPolicy ?? store.SpeedPolicy; entity.DefaultLanguage = invoice.Checkout.DefaultLanguage; entity.DefaultPaymentMethod = invoice.Checkout.DefaultPaymentMethod; entity.RedirectAutomatically = invoice.Checkout.RedirectAutomatically ?? storeBlob.RedirectAutomatically; entity.RequiresRefundEmail = invoice.Checkout.RequiresRefundEmail; IPaymentFilter?excludeFilter = null; if (invoice.Checkout.PaymentMethods != null) { var supportedTransactionCurrencies = invoice.Checkout.PaymentMethods .Select(c => PaymentMethodId.TryParse(c, out var p) ? p : null) .ToHashSet(); excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p)); } entity.PaymentTolerance = invoice.Checkout.PaymentTolerance ?? storeBlob.PaymentTolerance; entity.RedirectURLTemplate = invoice.Checkout.RedirectURL?.Trim(); entity.RequiresRefundEmail = invoice.Checkout.RequiresRefundEmail; if (additionalTags != null) { entity.InternalTags.AddRange(additionalTags); } return(await CreateInvoiceCoreRaw(entity, store, excludeFilter, invoice.AdditionalSearchTerms, cancellationToken)); }
private async Task <PaymentMethod?> CreatePaymentMethodAsync(Dictionary <CurrencyPair, Task <RateResult> > fetchingByCurrencyPair, IPaymentMethodHandler handler, ISupportedPaymentMethod supportedPaymentMethod, BTCPayNetworkBase network, InvoiceEntity entity, StoreData store, InvoiceLogs logs) { try { var logPrefix = $"{supportedPaymentMethod.PaymentId.ToPrettyString()}:"; var storeBlob = store.GetStoreBlob(); object?preparePayment; if (storeBlob.LazyPaymentMethods) { preparePayment = null; } else { preparePayment = handler.PreparePayment(supportedPaymentMethod, store, network); } var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.Currency)]; if (rate.BidAsk == null) { return(null); } var paymentMethod = new PaymentMethod { ParentEntity = entity, Network = network, Rate = rate.BidAsk.Bid, PreferOnion = Uri.TryCreate(entity.ServerUrl, UriKind.Absolute, out var u) && u.DnsSafeHost.EndsWith(".onion", StringComparison.OrdinalIgnoreCase) }; paymentMethod.SetId(supportedPaymentMethod.PaymentId); using (logs.Measure($"{logPrefix} Payment method details creation")) { var paymentDetails = await handler.CreatePaymentMethodDetails(logs, supportedPaymentMethod, paymentMethod, store, network, preparePayment); paymentMethod.SetPaymentMethodDetails(paymentDetails); } var criteria = storeBlob.PaymentMethodCriteria?.Find(methodCriteria => methodCriteria.PaymentMethod == supportedPaymentMethod.PaymentId); if (criteria?.Value != null && entity.Type != InvoiceType.TopUp) { var currentRateToCrypto = await fetchingByCurrencyPair[new CurrencyPair(supportedPaymentMethod.PaymentId.CryptoCode, criteria.Value.Currency)]; if (currentRateToCrypto?.BidAsk != null) { var amount = paymentMethod.Calculate().Due.GetValue(network as BTCPayNetwork); var limitValueCrypto = criteria.Value.Value / currentRateToCrypto.BidAsk.Bid; if (amount < limitValueCrypto && criteria.Above) { logs.Write($"{logPrefix} invoice amount below accepted value for payment method", InvoiceEventData.EventSeverity.Error); return(null); } if (amount > limitValueCrypto && !criteria.Above) { logs.Write($"{logPrefix} invoice amount above accepted value for payment method", InvoiceEventData.EventSeverity.Error); return(null); } } else { var suffix = currentRateToCrypto?.EvaluatedRule is string s ? $" ({s})" : string.Empty; logs.Write($"{logPrefix} This payment method should be created only if the amount of this invoice is in proper range. However, we are unable to fetch the rate of those limits. {suffix}", InvoiceEventData.EventSeverity.Warning); } } #pragma warning disable CS0618 if (paymentMethod.GetId().IsBTCOnChain) { entity.TxFee = paymentMethod.NextNetworkFee; entity.Rate = paymentMethod.Rate; entity.DepositAddress = paymentMethod.DepositAddress; } #pragma warning restore CS0618 return(paymentMethod); } catch (PaymentMethodUnavailableException ex) { logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Payment method unavailable ({ex.Message})", InvoiceEventData.EventSeverity.Error); } catch (Exception ex) { logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Unexpected exception ({ex})", InvoiceEventData.EventSeverity.Error); } return(null); }
public static IEnumerable <LNURLPayPaymentMethodData> GetLNURLPayPaymentMethods(StoreData store, BTCPayNetworkProvider networkProvider, bool?enabled) { var blob = store.GetStoreBlob(); var excludedPaymentMethods = blob.GetExcludedPaymentMethods(); return(store.GetSupportedPaymentMethods(networkProvider) .Where((method) => method.PaymentId.PaymentType == PaymentTypes.LNURLPay) .OfType <LNURLPaySupportedPaymentMethod>() .Select(paymentMethod => new LNURLPayPaymentMethodData( paymentMethod.PaymentId.CryptoCode, !excludedPaymentMethods.Match(paymentMethod.PaymentId), paymentMethod.UseBech32Scheme, paymentMethod.EnableForStandardInvoices ) ) .Where((result) => enabled is null || enabled == result.Enabled) .ToList()); }
public override async Task <IPaymentMethodDetails> CreatePaymentMethodDetails( InvoiceLogs logs, DerivationSchemeSettings supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store, BTCPayNetwork network, object preparePaymentObject) { if (!_ExplorerProvider.IsAvailable(network)) { throw new PaymentMethodUnavailableException($"Full node not available"); } var prepare = (Prepare)preparePaymentObject; Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod onchainMethod = new Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod(); var blob = store.GetStoreBlob(); onchainMethod.NetworkFeeMode = blob.NetworkFeeMode; onchainMethod.FeeRate = await prepare.GetFeeRate; switch (onchainMethod.NetworkFeeMode) { case NetworkFeeMode.Always: onchainMethod.NetworkFeeRate = (await prepare.GetNetworkFeeRate); onchainMethod.NextNetworkFee = onchainMethod.NetworkFeeRate.GetFee(100); // assume price for 100 bytes break; case NetworkFeeMode.Never: onchainMethod.NetworkFeeRate = FeeRate.Zero; onchainMethod.NextNetworkFee = Money.Zero; break; case NetworkFeeMode.MultiplePaymentsOnly: onchainMethod.NetworkFeeRate = (await prepare.GetNetworkFeeRate); onchainMethod.NextNetworkFee = Money.Zero; break; } onchainMethod.DepositAddress = (await prepare.ReserveAddress).Address.ToString(); onchainMethod.PayjoinEnabled = blob.PayJoinEnabled && PayjoinClient.SupportedFormats.Contains(supportedPaymentMethod .AccountDerivation.ScriptPubKeyType()) && network.SupportPayJoin; if (onchainMethod.PayjoinEnabled) { var prefix = $"{supportedPaymentMethod.PaymentId.ToPrettyString()}:"; var nodeSupport = _dashboard?.Get(network.CryptoCode)?.Status?.BitcoinStatus?.Capabilities ?.CanSupportTransactionCheck is true; onchainMethod.PayjoinEnabled &= supportedPaymentMethod.IsHotWallet && nodeSupport; if (!isHotwallet) { logs.Write($"{prefix} Payjoin should have been enabled, but your store is not a hotwallet"); } if (!nodeSupport) { logs.Write($"{prefix} Payjoin should have been enabled, but your version of NBXplorer or full node does not support it."); } if (onchainMethod.PayjoinEnabled) { logs.Write($"{prefix} Payjoin is enabled for this invoice."); } } return(onchainMethod); }
private LightningNetworkPaymentMethodData GetExistingLightningLikePaymentMethod(string cryptoCode, StoreData store = null) { store ??= Store; var storeBlob = store.GetStoreBlob(); var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); var paymentMethod = store .GetSupportedPaymentMethods(_btcPayNetworkProvider) .OfType <LightningSupportedPaymentMethod>() .FirstOrDefault(method => method.PaymentId == id); var excluded = storeBlob.IsExcluded(id); return(paymentMethod == null ? null : new LightningNetworkPaymentMethodData(paymentMethod.PaymentId.CryptoCode, paymentMethod.GetLightningUrl().ToString(), !excluded)); }
public static IEnumerable <OnChainPaymentMethodData> GetOnChainPaymentMethods(StoreData store, BTCPayNetworkProvider networkProvider, bool?enabled) { var blob = store.GetStoreBlob(); var excludedPaymentMethods = blob.GetExcludedPaymentMethods(); return(store.GetSupportedPaymentMethods(networkProvider) .Where((method) => method.PaymentId.PaymentType == PaymentTypes.BTCLike) .OfType <DerivationSchemeSettings>() .Select(strategy => new OnChainPaymentMethodData(strategy.PaymentId.CryptoCode, strategy.AccountDerivation.ToString(), !excludedPaymentMethods.Match(strategy.PaymentId), strategy.Label, strategy.GetSigningAccountKeySettings().GetRootedKeyPath(), strategy.PaymentId.ToStringNormalized())) .Where((result) => enabled is null || enabled == result.Enabled) .ToList()); }
public static IEnumerable <ISupportedPaymentMethod> GetSupportedPaymentMethods(this StoreData storeData, BTCPayNetworkProvider networks) { ArgumentNullException.ThrowIfNull(storeData); #pragma warning disable CS0618 bool btcReturned = false; if (!string.IsNullOrEmpty(storeData.DerivationStrategies)) { JObject strategies = JObject.Parse(storeData.DerivationStrategies); foreach (var strat in strategies.Properties()) { if (!PaymentMethodId.TryParse(strat.Name, out var paymentMethodId)) { continue; } var network = networks.GetNetwork <BTCPayNetworkBase>(paymentMethodId.CryptoCode); if (network != null) { if (network == networks.BTC && paymentMethodId.PaymentType == PaymentTypes.BTCLike && btcReturned) { continue; } if (strat.Value.Type == JTokenType.Null) { continue; } yield return (paymentMethodId.PaymentType.DeserializeSupportedPaymentMethod(network, strat.Value)); } } } #pragma warning restore CS0618 }
public static bool HasClaim(this StoreData storeData, string claim) { return(storeData.GetClaims().Any(c => c.Type == claim && c.Value == storeData.Id)); }
public static IEnumerable <ISupportedPaymentMethod> GetSupportedPaymentMethods(this StoreData storeData, BTCPayNetworkProvider networks) { networks = networks.UnfilteredNetworks; #pragma warning disable CS0618 bool btcReturned = false; // Legacy stuff which should go away if (!string.IsNullOrEmpty(storeData.DerivationStrategy)) { btcReturned = true; yield return(DerivationSchemeSettings.Parse(storeData.DerivationStrategy, networks.BTC)); } if (!string.IsNullOrEmpty(storeData.DerivationStrategies)) { JObject strategies = JObject.Parse(storeData.DerivationStrategies); foreach (var strat in strategies.Properties()) { var paymentMethodId = PaymentMethodId.Parse(strat.Name); var network = networks.GetNetwork <BTCPayNetworkBase>(paymentMethodId.CryptoCode); if (network != null) { if (network == networks.BTC && paymentMethodId.PaymentType == PaymentTypes.BTCLike && btcReturned) { continue; } if (strat.Value.Type == JTokenType.Null) { continue; } yield return (paymentMethodId.PaymentType.DeserializeSupportedPaymentMethod(network, strat.Value)); } } } #pragma warning restore CS0618 }
private OnChainPaymentMethodData GetExistingBtcLikePaymentMethod(string cryptoCode, StoreData store = null) { store ??= Store; var storeBlob = store.GetStoreBlob(); var id = new PaymentMethodId(cryptoCode, PaymentTypes.BTCLike); var paymentMethod = store .GetSupportedPaymentMethods(_btcPayNetworkProvider) .OfType <DerivationSchemeSettings>() .FirstOrDefault(method => method.PaymentId == id); var excluded = storeBlob.IsExcluded(id); return(paymentMethod == null ? null : new OnChainPaymentMethodData(paymentMethod.PaymentId.CryptoCode, paymentMethod.AccountDerivation.ToString(), !excluded) { Label = paymentMethod.Label, AccountKeyPath = paymentMethod.GetSigningAccountKeySettings().GetRootedKeyPath() }); }
private async Task <PaymentMethod> CreatePaymentMethodAsync(Dictionary <CurrencyPair, Task <RateResult> > fetchingByCurrencyPair, IPaymentMethodHandler handler, ISupportedPaymentMethod supportedPaymentMethod, BTCPayNetworkBase network, InvoiceEntity entity, StoreData store, InvoiceLogs logs) { try { var logPrefix = $"{supportedPaymentMethod.PaymentId.ToPrettyString()}:"; var storeBlob = store.GetStoreBlob(); var preparePayment = handler.PreparePayment(supportedPaymentMethod, store, network); var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.ProductInformation.Currency)]; if (rate.BidAsk == null) { return(null); } PaymentMethod paymentMethod = new PaymentMethod(); paymentMethod.ParentEntity = entity; paymentMethod.Network = network; paymentMethod.SetId(supportedPaymentMethod.PaymentId); paymentMethod.Rate = rate.BidAsk.Bid; paymentMethod.PreferOnion = Uri.TryCreate(entity.ServerUrl, UriKind.Absolute, out var u) && u.DnsSafeHost.EndsWith(".onion", StringComparison.OrdinalIgnoreCase); using (logs.Measure($"{logPrefix} Payment method details creation")) { var paymentDetails = await handler.CreatePaymentMethodDetails(logs, supportedPaymentMethod, paymentMethod, store, network, preparePayment); paymentMethod.SetPaymentMethodDetails(paymentDetails); } var errorMessage = await handler .IsPaymentMethodAllowedBasedOnInvoiceAmount(storeBlob, fetchingByCurrencyPair, paymentMethod.Calculate().Due, supportedPaymentMethod.PaymentId); if (!string.IsNullOrEmpty(errorMessage)) { logs.Write($"{logPrefix} {errorMessage}"); return(null); } #pragma warning disable CS0618 if (paymentMethod.GetId().IsBTCOnChain) { entity.TxFee = paymentMethod.NextNetworkFee; entity.Rate = paymentMethod.Rate; entity.DepositAddress = paymentMethod.DepositAddress; } #pragma warning restore CS0618 return(paymentMethod); } catch (PaymentMethodUnavailableException ex) { logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Payment method unavailable ({ex.Message})"); } catch (Exception ex) { logs.Write($"{supportedPaymentMethod.PaymentId.CryptoCode}: Unexpected exception ({ex.ToString()})"); } return(null); }
public override object PreparePayment(DerivationSchemeSettings supportedPaymentMethod, StoreData store, BTCPayNetworkBase network) { var storeBlob = store.GetStoreBlob(); return(new Prepare() { GetFeeRate = _FeeRateProviderFactory.CreateFeeProvider(network) .GetFeeRateAsync(storeBlob.RecommendedFeeBlockTarget), GetNetworkFeeRate = storeBlob.NetworkFeeMode == NetworkFeeMode.Never ? null : _FeeRateProviderFactory.CreateFeeProvider(network).GetFeeRateAsync(), ReserveAddress = _WalletProvider.GetWallet(network) .ReserveAddressAsync(supportedPaymentMethod.AccountDerivation) }); }
internal async Task <DataWrapper <InvoiceResponse> > CreateInvoiceCore(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List <string> additionalTags = null, CancellationToken cancellationToken = default) { invoice.Currency = invoice.Currency?.ToUpperInvariant() ?? "USD"; InvoiceLogs logs = new InvoiceLogs(); logs.Write("Creation of invoice starting"); var entity = _InvoiceRepository.CreateNewInvoice(); var getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id); var storeBlob = store.GetStoreBlob(); EmailAddressAttribute emailValidator = new EmailAddressAttribute(); entity.ExpirationTime = invoice.ExpirationTime is DateTimeOffset v ? v : entity.InvoiceTime.AddMinutes(storeBlob.InvoiceExpiration); if (entity.ExpirationTime - TimeSpan.FromSeconds(30.0) < entity.InvoiceTime) { throw new BitpayHttpException(400, "The expirationTime is set too soon"); } entity.MonitoringExpiration = entity.ExpirationTime + TimeSpan.FromMinutes(storeBlob.MonitoringExpiration); entity.OrderId = invoice.OrderId; entity.ServerUrl = serverUrl; entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications; entity.ExtendedNotifications = invoice.ExtendedNotifications; entity.NotificationURLTemplate = invoice.NotificationURL; entity.NotificationEmail = invoice.NotificationEmail; entity.BuyerInformation = Map <CreateInvoiceRequest, BuyerInformation>(invoice); entity.PaymentTolerance = storeBlob.PaymentTolerance; if (additionalTags != null) { entity.InternalTags.AddRange(additionalTags); } //Another way of passing buyer info to support FillBuyerInfo(invoice.Buyer, entity.BuyerInformation); if (entity?.BuyerInformation?.BuyerEmail != null) { if (!EmailValidator.IsEmail(entity.BuyerInformation.BuyerEmail)) { throw new BitpayHttpException(400, "Invalid email"); } entity.RefundMail = entity.BuyerInformation.BuyerEmail; } var taxIncluded = invoice.TaxIncluded.HasValue ? invoice.TaxIncluded.Value : 0m; var currencyInfo = _CurrencyNameTable.GetNumberFormatInfo(invoice.Currency, false); if (currencyInfo != null) { int divisibility = currencyInfo.CurrencyDecimalDigits; invoice.Price = invoice.Price.RoundToSignificant(ref divisibility); divisibility = currencyInfo.CurrencyDecimalDigits; invoice.TaxIncluded = taxIncluded.RoundToSignificant(ref divisibility); } invoice.Price = Math.Max(0.0m, invoice.Price); invoice.TaxIncluded = Math.Max(0.0m, taxIncluded); invoice.TaxIncluded = Math.Min(taxIncluded, invoice.Price); entity.ProductInformation = Map <CreateInvoiceRequest, ProductInformation>(invoice); entity.RedirectURLTemplate = invoice.RedirectURL ?? store.StoreWebsite; entity.RedirectAutomatically = invoice.RedirectAutomatically.GetValueOrDefault(storeBlob.RedirectAutomatically); entity.Status = InvoiceStatus.New; entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy); HashSet <CurrencyPair> currencyPairsToFetch = new HashSet <CurrencyPair>(); var rules = storeBlob.GetRateRules(_NetworkProvider); var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any() if (invoice.PaymentCurrencies?.Any() is true) { foreach (string paymentCurrency in invoice.PaymentCurrencies) { invoice.SupportedTransactionCurrencies.TryAdd(paymentCurrency, new InvoiceSupportedTransactionCurrency() { Enabled = true }); } } if (invoice.SupportedTransactionCurrencies != null && invoice.SupportedTransactionCurrencies.Count != 0) { var supportedTransactionCurrencies = invoice.SupportedTransactionCurrencies .Where(c => c.Value.Enabled) .Select(c => PaymentMethodId.TryParse(c.Key, out var p) ? p : null) .ToHashSet(); excludeFilter = PaymentFilter.Or(excludeFilter, PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p))); } foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider) .Where(s => !excludeFilter.Match(s.PaymentId)) .Select(c => _NetworkProvider.GetNetwork <BTCPayNetworkBase>(c.PaymentId.CryptoCode)) .Where(c => c != null)) { currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, invoice.Currency)); //TODO: abstract if (storeBlob.LightningMaxValue != null) { currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, storeBlob.LightningMaxValue.Currency)); } if (storeBlob.OnChainMinValue != null) { currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, storeBlob.OnChainMinValue.Currency)); } } var rateRules = storeBlob.GetRateRules(_NetworkProvider); var fetchingByCurrencyPair = _RateProvider.FetchRates(currencyPairsToFetch, rateRules, cancellationToken); var fetchingAll = WhenAllFetched(logs, fetchingByCurrencyPair); var supportedPaymentMethods = store.GetSupportedPaymentMethods(_NetworkProvider) .Where(s => !excludeFilter.Match(s.PaymentId) && _paymentMethodHandlerDictionary.Support(s.PaymentId)) .Select(c => (Handler: _paymentMethodHandlerDictionary[c.PaymentId], SupportedPaymentMethod: c, Network: _NetworkProvider.GetNetwork <BTCPayNetworkBase>(c.PaymentId.CryptoCode))) .Where(c => c.Network != null) .Select(o => (SupportedPaymentMethod: o.SupportedPaymentMethod, PaymentMethod: CreatePaymentMethodAsync(fetchingByCurrencyPair, o.Handler, o.SupportedPaymentMethod, o.Network, entity, store, logs))) .ToList(); List <ISupportedPaymentMethod> supported = new List <ISupportedPaymentMethod>(); var paymentMethods = new PaymentMethodDictionary(); foreach (var o in supportedPaymentMethods) { var paymentMethod = await o.PaymentMethod; if (paymentMethod == null) { continue; } supported.Add(o.SupportedPaymentMethod); paymentMethods.Add(paymentMethod); } if (supported.Count == 0) { StringBuilder errors = new StringBuilder(); if (!store.GetSupportedPaymentMethods(_NetworkProvider).Any()) { errors.AppendLine("Warning: No wallet has been linked to your BTCPay Store. See the following link for more information on how to connect your store and wallet. (https://docs.btcpayserver.org/getting-started/connectwallet)"); } foreach (var error in logs.ToList()) { errors.AppendLine(error.ToString()); } throw new BitpayHttpException(400, errors.ToString()); } entity.SetSupportedPaymentMethods(supported); entity.SetPaymentMethods(paymentMethods); entity.PosData = invoice.PosData; foreach (var app in await getAppsTaggingStore) { entity.InternalTags.Add(AppService.GetAppInternalTag(app.Id)); } using (logs.Measure("Saving invoice")) { entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity); } _ = Task.Run(async() => { try { await fetchingAll; } catch (AggregateException ex) { ex.Handle(e => { logs.Write($"Error while fetching rates {ex}"); return(true); }); } await _InvoiceRepository.AddInvoiceLogs(entity.Id, logs); }); _EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, InvoiceEvent.Created)); var resp = entity.EntityToDTO(); return(new DataWrapper <InvoiceResponse>(resp) { Facade = "pos/invoice" }); }
public Task <IEnumerable <PaymentMethodId> > GetSupportedPaymentMethods(StoreData storeData) { return(Task.FromResult(storeData.GetEnabledPaymentIds(_btcPayNetworkProvider) .Where(id => id.PaymentType == BitcoinPaymentType.Instance))); }
public static PaymentMethodId?GetDefaultPaymentId(this StoreData storeData) { PaymentMethodId.TryParse(storeData.DefaultCrypto, out var defaultPaymentId); return(defaultPaymentId); }
internal async Task <InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter?invoicePaymentMethodFilter, string[]?additionalSearchTerms = null, CancellationToken cancellationToken = default) { InvoiceLogs logs = new InvoiceLogs(); logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info); var storeBlob = store.GetStoreBlob(); if (string.IsNullOrEmpty(entity.Currency)) { entity.Currency = storeBlob.DefaultCurrency; } entity.Currency = entity.Currency.Trim().ToUpperInvariant(); entity.Price = Math.Max(0.0m, entity.Price); var currencyInfo = _CurrencyNameTable.GetNumberFormatInfo(entity.Currency, false); if (currencyInfo != null) { entity.Price = entity.Price.RoundToSignificant(currencyInfo.CurrencyDecimalDigits); } if (entity.Metadata.TaxIncluded is decimal taxIncluded) { if (currencyInfo != null) { taxIncluded = taxIncluded.RoundToSignificant(currencyInfo.CurrencyDecimalDigits); } taxIncluded = Math.Max(0.0m, taxIncluded); taxIncluded = Math.Min(taxIncluded, entity.Price); entity.Metadata.TaxIncluded = taxIncluded; } var getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id); if (entity.Metadata.BuyerEmail != null) { if (!EmailValidator.IsEmail(entity.Metadata.BuyerEmail)) { throw new BitpayHttpException(400, "Invalid email"); } entity.RefundMail = entity.Metadata.BuyerEmail; } entity.Status = InvoiceStatusLegacy.New; HashSet <CurrencyPair> currencyPairsToFetch = new HashSet <CurrencyPair>(); var rules = storeBlob.GetRateRules(_NetworkProvider); var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any() if (invoicePaymentMethodFilter != null) { excludeFilter = PaymentFilter.Or(excludeFilter, invoicePaymentMethodFilter); } foreach (var network in store.GetSupportedPaymentMethods(_NetworkProvider) .Where(s => !excludeFilter.Match(s.PaymentId)) .Select(c => _NetworkProvider.GetNetwork <BTCPayNetworkBase>(c.PaymentId.CryptoCode)) .Where(c => c != null)) { currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, entity.Currency)); foreach (var paymentMethodCriteria in storeBlob.PaymentMethodCriteria) { if (paymentMethodCriteria.Value != null) { currencyPairsToFetch.Add(new CurrencyPair(network.CryptoCode, paymentMethodCriteria.Value.Currency)); } } } var rateRules = storeBlob.GetRateRules(_NetworkProvider); var fetchingByCurrencyPair = _RateProvider.FetchRates(currencyPairsToFetch, rateRules, cancellationToken); var fetchingAll = WhenAllFetched(logs, fetchingByCurrencyPair); List <ISupportedPaymentMethod> supported = new List <ISupportedPaymentMethod>(); var paymentMethods = new PaymentMethodDictionary(); bool noNeedForMethods = entity.Type != InvoiceType.TopUp && entity.Price == 0m; if (!noNeedForMethods) { // This loop ends with .ToList so we are querying all payment methods at once // instead of sequentially to improve response time foreach (var o in store.GetSupportedPaymentMethods(_NetworkProvider) .Where(s => !excludeFilter.Match(s.PaymentId) && _paymentMethodHandlerDictionary.Support(s.PaymentId)) .Select(c => (Handler: _paymentMethodHandlerDictionary[c.PaymentId], SupportedPaymentMethod: c, Network: _NetworkProvider.GetNetwork <BTCPayNetworkBase>(c.PaymentId.CryptoCode))) .Where(c => c.Network != null) .Select(o => (SupportedPaymentMethod: o.SupportedPaymentMethod, PaymentMethod: CreatePaymentMethodAsync(fetchingByCurrencyPair, o.Handler, o.SupportedPaymentMethod, o.Network, entity, store, logs))) .ToList()) { var paymentMethod = await o.PaymentMethod; if (paymentMethod == null) { continue; } supported.Add(o.SupportedPaymentMethod); paymentMethods.Add(paymentMethod); } if (supported.Count == 0) { StringBuilder errors = new StringBuilder(); if (!store.GetSupportedPaymentMethods(_NetworkProvider).Any()) { errors.AppendLine( "Warning: No wallet has been linked to your BTCPay Store. See the following link for more information on how to connect your store and wallet. (https://docs.btcpayserver.org/WalletSetup/)"); } foreach (var error in logs.ToList()) { errors.AppendLine(error.ToString()); } throw new BitpayHttpException(400, errors.ToString()); } } entity.SetSupportedPaymentMethods(supported); entity.SetPaymentMethods(paymentMethods); foreach (var app in await getAppsTaggingStore) { entity.InternalTags.Add(AppService.GetAppInternalTag(app.Id)); } using (logs.Measure("Saving invoice")) { entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, additionalSearchTerms); } _ = Task.Run(async() => { try { await fetchingAll; } catch (AggregateException ex) { ex.Handle(e => { logs.Write($"Error while fetching rates {ex}", InvoiceEventData.EventSeverity.Error); return(true); }); } await _InvoiceRepository.AddInvoiceLogs(entity.Id, logs); }); _EventAggregator.Publish(new Events.InvoiceEvent(entity, InvoiceEvent.Created)); return(entity); }
internal async Task <InvoiceEntity> CreateInvoiceCoreRaw(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List <string> additionalTags = null, CancellationToken cancellationToken = default) { var storeBlob = store.GetStoreBlob(); var entity = _InvoiceRepository.CreateNewInvoice(); entity.ExpirationTime = invoice.ExpirationTime is DateTimeOffset v ? v : entity.InvoiceTime + storeBlob.InvoiceExpiration; entity.MonitoringExpiration = entity.ExpirationTime + storeBlob.MonitoringExpiration; if (entity.ExpirationTime - TimeSpan.FromSeconds(30.0) < entity.InvoiceTime) { throw new BitpayHttpException(400, "The expirationTime is set too soon"); } invoice.Currency = invoice.Currency?.Trim().ToUpperInvariant() ?? "USD"; entity.Metadata.OrderId = invoice.OrderId; entity.Metadata.PosData = invoice.PosData; entity.ServerUrl = serverUrl; entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications; entity.ExtendedNotifications = invoice.ExtendedNotifications; entity.NotificationURLTemplate = invoice.NotificationURL; entity.NotificationEmail = invoice.NotificationEmail; if (additionalTags != null) { entity.InternalTags.AddRange(additionalTags); } FillBuyerInfo(invoice, entity); var taxIncluded = invoice.TaxIncluded.HasValue ? invoice.TaxIncluded.Value : 0m; var currencyInfo = _CurrencyNameTable.GetNumberFormatInfo(invoice.Currency, false); if (currencyInfo != null) { int divisibility = currencyInfo.CurrencyDecimalDigits; invoice.Price = invoice.Price.RoundToSignificant(ref divisibility); divisibility = currencyInfo.CurrencyDecimalDigits; invoice.TaxIncluded = taxIncluded.RoundToSignificant(ref divisibility); } invoice.Price = Math.Max(0.0m, invoice.Price); invoice.TaxIncluded = Math.Max(0.0m, taxIncluded); invoice.TaxIncluded = Math.Min(taxIncluded, invoice.Price); entity.Metadata.ItemCode = invoice.ItemCode; entity.Metadata.ItemDesc = invoice.ItemDesc; entity.Metadata.Physical = invoice.Physical; entity.Metadata.TaxIncluded = invoice.TaxIncluded; entity.Currency = invoice.Currency; entity.Price = invoice.Price; entity.RedirectURLTemplate = invoice.RedirectURL ?? store.StoreWebsite; entity.RedirectAutomatically = invoice.RedirectAutomatically.GetValueOrDefault(storeBlob.RedirectAutomatically); entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy); IPaymentFilter excludeFilter = null; if (invoice.PaymentCurrencies?.Any() is true) { invoice.SupportedTransactionCurrencies ??= new Dictionary <string, InvoiceSupportedTransactionCurrency>(); foreach (string paymentCurrency in invoice.PaymentCurrencies) { invoice.SupportedTransactionCurrencies.TryAdd(paymentCurrency, new InvoiceSupportedTransactionCurrency() { Enabled = true }); } } if (invoice.SupportedTransactionCurrencies != null && invoice.SupportedTransactionCurrencies.Count != 0) { var supportedTransactionCurrencies = invoice.SupportedTransactionCurrencies .Where(c => c.Value.Enabled) .Select(c => PaymentMethodId.TryParse(c.Key, out var p) ? p : null) .Where(c => c != null) .ToHashSet(); excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p)); } entity.PaymentTolerance = storeBlob.PaymentTolerance; return(await CreateInvoiceCoreRaw(entity, store, excludeFilter, cancellationToken)); }
public static PaymentMethodId[] GetEnabledPaymentIds(this StoreData storeData, BTCPayNetworkProvider networks) { return(GetEnabledPaymentMethods(storeData, networks).Select(method => method.PaymentId).ToArray()); }
public static LightningNetworkPaymentMethodData?GetExistingLightningLikePaymentMethod(BTCPayNetworkProvider btcPayNetworkProvider, string cryptoCode, StoreData store) { var storeBlob = store.GetStoreBlob(); var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); var paymentMethod = store .GetSupportedPaymentMethods(btcPayNetworkProvider) .OfType <LightningSupportedPaymentMethod>() .FirstOrDefault(method => method.PaymentId == id); var excluded = storeBlob.IsExcluded(id); return(paymentMethod is null ? null : new LightningNetworkPaymentMethodData(paymentMethod.PaymentId.CryptoCode, paymentMethod.GetDisplayableConnectionString(), !excluded, paymentMethod.PaymentId.ToStringNormalized(), paymentMethod.DisableBOLT11PaymentOption)); }
internal async Task <InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List <string> additionalTags = null, CancellationToken cancellationToken = default) { var storeBlob = store.GetStoreBlob(); var entity = _InvoiceRepository.CreateNewInvoice(); entity.ExpirationTime = entity.InvoiceTime + (invoice.Checkout.Expiration ?? storeBlob.InvoiceExpiration); entity.MonitoringExpiration = entity.ExpirationTime + (invoice.Checkout.Monitoring ?? storeBlob.MonitoringExpiration); if (invoice.Metadata != null) { entity.Metadata = InvoiceMetadata.FromJObject(invoice.Metadata); } invoice.Checkout ??= new CreateInvoiceRequest.CheckoutOptions(); invoice.Currency = invoice.Currency?.Trim().ToUpperInvariant() ?? "USD"; entity.Currency = invoice.Currency; entity.Price = invoice.Amount; entity.SpeedPolicy = invoice.Checkout.SpeedPolicy ?? store.SpeedPolicy; entity.DefaultLanguage = invoice.Checkout.DefaultLanguage; IPaymentFilter excludeFilter = null; if (invoice.Checkout.PaymentMethods != null) { var supportedTransactionCurrencies = invoice.Checkout.PaymentMethods .Select(c => PaymentMethodId.TryParse(c, out var p) ? p : null) .ToHashSet(); excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p)); } entity.PaymentTolerance = invoice.Checkout.PaymentTolerance ?? storeBlob.PaymentTolerance; entity.RedirectURLTemplate = invoice.Checkout.RedirectURL?.Trim(); if (additionalTags != null) { entity.InternalTags.AddRange(additionalTags); } return(await CreateInvoiceCoreRaw(entity, store, excludeFilter, cancellationToken)); }
public static void SetSupportedPaymentMethod(this StoreData storeData, ISupportedPaymentMethod supportedPaymentMethod) { storeData.SetSupportedPaymentMethod(null, supportedPaymentMethod); }