Beispiel #1
0
        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)));
        }
Beispiel #5
0
    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));
    }
Beispiel #6
0
        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());
        }
Beispiel #7
0
        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));
        }
Beispiel #9
0
 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);
        }
Beispiel #12
0
        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);
        }
Beispiel #14
0
        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));
        }
Beispiel #15
0
        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));
 }
Beispiel #18
0
        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());
 }
Beispiel #28
0
        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));
        }
Beispiel #30
0
 public static void SetSupportedPaymentMethod(this StoreData storeData, ISupportedPaymentMethod supportedPaymentMethod)
 {
     storeData.SetSupportedPaymentMethod(null, supportedPaymentMethod);
 }