private async Task <PaymentModel> GetInvoiceModel(string invoiceId, string paymentMethodIdStr) { var invoice = await _InvoiceRepository.GetInvoice(invoiceId); if (invoice == null) { return(null); } var store = await _StoreRepository.FindStore(invoice.StoreId); bool isDefaultCrypto = false; if (paymentMethodIdStr == null) { paymentMethodIdStr = store.GetDefaultCrypto(_NetworkProvider); isDefaultCrypto = true; } var paymentMethodId = PaymentMethodId.Parse(paymentMethodIdStr); var network = _NetworkProvider.GetNetwork(paymentMethodId.CryptoCode); if (network == null && isDefaultCrypto) { network = _NetworkProvider.GetAll().FirstOrDefault(); paymentMethodId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike); paymentMethodIdStr = paymentMethodId.ToString(); } if (invoice == null || network == null) { return(null); } if (!invoice.Support(paymentMethodId)) { if (!isDefaultCrypto) { return(null); } var paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider) .Where(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode) .FirstOrDefault(); if (paymentMethodTemp == null) { paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider).First(); } network = paymentMethodTemp.Network; paymentMethodId = paymentMethodTemp.GetId(); paymentMethodIdStr = paymentMethodId.ToString(); } var paymentMethod = invoice.GetPaymentMethod(paymentMethodId, _NetworkProvider); var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails(); var dto = invoice.EntityToDTO(_NetworkProvider); var cryptoInfo = dto.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId); var storeBlob = store.GetStoreBlob(); var currency = invoice.ProductInformation.Currency; var accounting = paymentMethod.Calculate(); ChangellySettings changelly = (storeBlob.ChangellySettings != null && storeBlob.ChangellySettings.Enabled && storeBlob.ChangellySettings.IsConfigured()) ? storeBlob.ChangellySettings : null; var changellyAmountDue = changelly != null ? (accounting.Due.ToDecimal(MoneyUnit.BTC) * (1m + (changelly.AmountMarkupPercentage / 100m))) : (decimal?)null; var model = new PaymentModel() { CryptoCode = network.CryptoCode, PaymentMethodId = paymentMethodId.ToString(), PaymentMethodName = GetDisplayName(paymentMethodId, network), CryptoImage = GetImage(paymentMethodId, network), IsLightning = paymentMethodId.PaymentType == PaymentTypes.LightningLike, ServerUrl = HttpContext.Request.GetAbsoluteRoot(), OrderId = invoice.OrderId, InvoiceId = invoice.Id, DefaultLang = storeBlob.DefaultLang ?? "en", HtmlTitle = storeBlob.HtmlTitle ?? "BTCPay Invoice", CustomCSSLink = storeBlob.CustomCSS?.AbsoluteUri, CustomLogoLink = storeBlob.CustomLogo?.AbsoluteUri, BtcAddress = paymentMethodDetails.GetPaymentDestination(), BtcDue = accounting.Due.ToString(), OrderAmount = (accounting.TotalDue - accounting.NetworkFee).ToString(), OrderAmountFiat = OrderAmountFromInvoice(network.CryptoCode, invoice.ProductInformation), CustomerEmail = invoice.RefundMail, RequiresRefundEmail = storeBlob.RequiresRefundEmail, ExpirationSeconds = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds), MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds, MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes, ItemDesc = invoice.ProductInformation.ItemDesc, Rate = ExchangeRate(paymentMethod), MerchantRefLink = invoice.RedirectURL ?? "/", StoreName = store.StoreName, InvoiceBitcoinUrl = paymentMethodId.PaymentType == PaymentTypes.BTCLike ? cryptoInfo.PaymentUrls.BIP21 : paymentMethodId.PaymentType == PaymentTypes.LightningLike ? cryptoInfo.PaymentUrls.BOLT11 : throw new NotSupportedException(), PeerInfo = (paymentMethodDetails as LightningLikePaymentMethodDetails)?.NodeInfo, InvoiceBitcoinUrlQR = paymentMethodId.PaymentType == PaymentTypes.BTCLike ? cryptoInfo.PaymentUrls.BIP21 : paymentMethodId.PaymentType == PaymentTypes.LightningLike ? cryptoInfo.PaymentUrls.BOLT11.ToUpperInvariant() : throw new NotSupportedException(), TxCount = accounting.TxRequired, BtcPaid = accounting.Paid.ToString(), #pragma warning disable CS0618 // Type or member is obsolete Status = invoice.StatusString, #pragma warning restore CS0618 // Type or member is obsolete NetworkFee = paymentMethodDetails.GetNetworkFee(), IsMultiCurrency = invoice.GetPayments().Select(p => p.GetPaymentMethodId()).Concat(new[] { paymentMethod.GetId() }).Distinct().Count() > 1, ChangellyEnabled = changelly != null, ChangellyMerchantId = changelly?.ChangellyMerchantId, ChangellyAmountDue = changellyAmountDue, StoreId = store.Id, AvailableCryptos = invoice.GetPaymentMethods(_NetworkProvider) .Where(i => i.Network != null) .Select(kv => new PaymentModel.AvailableCrypto() { PaymentMethodId = kv.GetId().ToString(), CryptoCode = kv.GetId().CryptoCode, PaymentMethodName = GetDisplayName(kv.GetId(), kv.Network), IsLightning = kv.GetId().PaymentType == PaymentTypes.LightningLike, CryptoImage = GetImage(kv.GetId(), kv.Network), Link = Url.Action(nameof(Checkout), new { invoiceId = invoiceId, paymentMethodId = kv.GetId().ToString() }) }).Where(c => c.CryptoImage != "/") .OrderByDescending(a => a.CryptoCode == "BTC").ThenBy(a => a.PaymentMethodName).ThenBy(a => a.IsLightning ? 1 : 0) .ToList() }; var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds); model.TimeLeft = expiration.PrettyPrint(); return(model); }
public async Task <IActionResult> CheckoutExperience(CheckoutExperienceViewModel model) { CurrencyValue lightningMaxValue = null; if (!string.IsNullOrWhiteSpace(model.LightningMaxValue)) { if (!CurrencyValue.TryParse(model.LightningMaxValue, out lightningMaxValue)) { ModelState.AddModelError(nameof(model.LightningMaxValue), "Invalid lightning max value"); } } CurrencyValue onchainMinValue = null; if (!string.IsNullOrWhiteSpace(model.OnChainMinValue)) { if (!CurrencyValue.TryParse(model.OnChainMinValue, out onchainMinValue)) { ModelState.AddModelError(nameof(model.OnChainMinValue), "Invalid on chain min value"); } } bool needUpdate = false; var blob = StoreData.GetStoreBlob(); var defaultPaymentMethodId = model.DefaultPaymentMethod == null ? null : PaymentMethodId.Parse(model.DefaultPaymentMethod); if (StoreData.GetDefaultPaymentId(_NetworkProvider) != defaultPaymentMethodId) { needUpdate = true; StoreData.SetDefaultPaymentId(defaultPaymentMethodId); } SetCryptoCurrencies(model, StoreData); model.SetLanguages(_LangService, model.DefaultLang); if (!ModelState.IsValid) { return(View(model)); } blob.CustomLogo = string.IsNullOrWhiteSpace(model.CustomLogo) ? null : new Uri(model.CustomLogo, UriKind.Absolute); blob.CustomCSS = string.IsNullOrWhiteSpace(model.CustomCSS) ? null : new Uri(model.CustomCSS, UriKind.Absolute); blob.HtmlTitle = string.IsNullOrWhiteSpace(model.HtmlTitle) ? null : model.HtmlTitle; blob.DefaultLang = model.DefaultLang; blob.RequiresRefundEmail = model.RequiresRefundEmail; blob.OnChainMinValue = onchainMinValue; blob.LightningMaxValue = lightningMaxValue; blob.LightningAmountInSatoshi = model.LightningAmountInSatoshi; blob.RedirectAutomatically = model.RedirectAutomatically; if (StoreData.SetStoreBlob(blob)) { needUpdate = true; } if (needUpdate) { await _Repo.UpdateStore(StoreData); StatusMessage = "Store successfully updated"; } return(RedirectToAction(nameof(CheckoutExperience), new { storeId = StoreData.Id })); }
public async Task <IActionResult> GetLNURLForApp(string cryptoCode, string appId, string itemCode = null) { var network = _btcPayNetworkProvider.GetNetwork <BTCPayNetwork>(cryptoCode); if (network is null || !network.SupportLightning) { return(NotFound()); } var app = await _appService.GetApp(appId, null, true); if (app is null) { return(NotFound()); } var store = app.StoreData; if (store is null) { return(NotFound()); } if (string.IsNullOrEmpty(itemCode)) { return(NotFound()); } var pmi = new PaymentMethodId(cryptoCode, PaymentTypes.LNURLPay); var lnpmi = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike); var methods = store.GetSupportedPaymentMethods(_btcPayNetworkProvider); var lnUrlMethod = methods.FirstOrDefault(method => method.PaymentId == pmi) as LNURLPaySupportedPaymentMethod; var lnMethod = methods.FirstOrDefault(method => method.PaymentId == lnpmi); if (lnUrlMethod is null || lnMethod is null) { return(NotFound()); } ViewPointOfSaleViewModel.Item[] items = null; string currencyCode = null; switch (app.AppType) { case nameof(AppType.Crowdfund): var cfS = app.GetSettings <CrowdfundSettings>(); currencyCode = cfS.TargetCurrency; items = _appService.Parse(cfS.PerksTemplate, cfS.TargetCurrency); break; case nameof(AppType.PointOfSale): var posS = app.GetSettings <UIAppsController.PointOfSaleSettings>(); currencyCode = posS.Currency; items = _appService.Parse(posS.Template, posS.Currency); break; } var item = items.FirstOrDefault(item1 => item1.Id.Equals(itemCode, StringComparison.InvariantCultureIgnoreCase)); if (item is null || item.Inventory <= 0 || (item.PaymentMethods?.Any() is true && item.PaymentMethods?.Any(s => PaymentMethodId.Parse(s) == pmi) is false)) { return(NotFound()); } return(await GetLNURL(cryptoCode, app.StoreDataId, currencyCode, null, null, () => (null, new List <string> { AppService.GetAppInternalTag(appId) }, item.Price.Value, true))); }
private async Task <PaymentModel> GetInvoiceModel(string invoiceId, string paymentMethodIdStr) { var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId); if (invoice == null) { return(null); } var store = await _StoreRepository.FindStore(invoice.StoreId); bool isDefaultCrypto = false; if (paymentMethodIdStr == null) { paymentMethodIdStr = store.GetDefaultCrypto(); isDefaultCrypto = true; } var paymentMethodId = PaymentMethodId.Parse(paymentMethodIdStr); var network = _NetworkProvider.GetNetwork(paymentMethodId.CryptoCode); if (invoice == null || network == null) { return(null); } if (!invoice.Support(paymentMethodId)) { if (!isDefaultCrypto) { return(null); } var paymentMethodTemp = invoice.GetPaymentMethods(_NetworkProvider).First(); network = paymentMethodTemp.Network; paymentMethodId = paymentMethodTemp.GetId(); } var paymentMethod = invoice.GetPaymentMethod(paymentMethodId, _NetworkProvider); var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails(); var dto = invoice.EntityToDTO(_NetworkProvider); var cryptoInfo = dto.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId); var currency = invoice.ProductInformation.Currency; var accounting = paymentMethod.Calculate(); var model = new PaymentModel() { CryptoCode = network.CryptoCode, PaymentMethodId = paymentMethodId.ToString(), ServerUrl = HttpContext.Request.GetAbsoluteRoot(), OrderId = invoice.OrderId, InvoiceId = invoice.Id, BtcAddress = paymentMethodDetails.GetPaymentDestination(), OrderAmount = (accounting.TotalDue - accounting.NetworkFee).ToString(), BtcDue = accounting.Due.ToString(), CustomerEmail = invoice.RefundMail, ExpirationSeconds = Math.Max(0, (int)(invoice.ExpirationTime - DateTimeOffset.UtcNow).TotalSeconds), MaxTimeSeconds = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalSeconds, MaxTimeMinutes = (int)(invoice.ExpirationTime - invoice.InvoiceTime).TotalMinutes, ItemDesc = invoice.ProductInformation.ItemDesc, Rate = FormatCurrency(paymentMethod), MerchantRefLink = invoice.RedirectURL ?? "/", StoreName = store.StoreName, InvoiceBitcoinUrl = paymentMethodId.PaymentType == PaymentTypes.BTCLike ? cryptoInfo.PaymentUrls.BIP21 : paymentMethodId.PaymentType == PaymentTypes.LightningLike ? cryptoInfo.PaymentUrls.BOLT11 : throw new NotSupportedException(), InvoiceBitcoinUrlQR = paymentMethodId.PaymentType == PaymentTypes.BTCLike ? cryptoInfo.PaymentUrls.BIP21 : paymentMethodId.PaymentType == PaymentTypes.LightningLike ? cryptoInfo.PaymentUrls.BOLT11.ToUpperInvariant() : throw new NotSupportedException(), TxCount = accounting.TxRequired, BtcPaid = accounting.Paid.ToString(), Status = invoice.Status, CryptoImage = "/" + GetImage(paymentMethodId, network), NetworkFeeDescription = $"{accounting.TxRequired} transaction{(accounting.TxRequired > 1 ? "s" : "")} x {paymentMethodDetails.GetTxFee()} {network.CryptoCode}", AvailableCryptos = invoice.GetPaymentMethods(_NetworkProvider) .Where(i => i.Network != null) .Select(kv => new PaymentModel.AvailableCrypto() { PaymentMethodId = kv.GetId().ToString(), CryptoImage = "/" + GetImage(kv.GetId(), kv.Network), Link = Url.Action(nameof(Checkout), new { invoiceId = invoiceId, paymentMethodId = kv.GetId().ToString() }) }).Where(c => c.CryptoImage != "/") .ToList() }; var isMultiCurrency = invoice.GetPayments().Select(p => p.GetpaymentMethodId()).Concat(new[] { paymentMethod.GetId() }).Distinct().Count() > 1; if (isMultiCurrency) { model.NetworkFeeDescription = $"{accounting.NetworkFee} {network.CryptoCode}"; } var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds); model.TimeLeft = PrettyPrint(expiration); return(model); }
public async Task <IActionResult> CheckoutNoScript(string invoiceId, string id = null, string paymentMethodId = null) { //Keep compatibility with Bitpay invoiceId = invoiceId ?? id; id = invoiceId; // var model = await GetInvoiceModel(invoiceId, paymentMethodId == null?null : PaymentMethodId.Parse(paymentMethodId)); if (model == null) { return(NotFound()); } return(View(model)); }
public async Task <IActionResult> GetStatus(string invoiceId, string paymentMethodId = null) { var model = await GetInvoiceModel(invoiceId, paymentMethodId == null?null : PaymentMethodId.Parse(paymentMethodId)); if (model == null) { return(NotFound()); } return(Json(model)); }
public async Task <IActionResult> Checkout(string invoiceId, string id = null, string paymentMethodId = null, [FromQuery] string view = null) { //Keep compatibility with Bitpay invoiceId = invoiceId ?? id; id = invoiceId; // var model = await GetInvoiceModel(invoiceId, paymentMethodId == null?null : PaymentMethodId.Parse(paymentMethodId)); if (model == null) { return(NotFound()); } if (view == "modal") { model.IsModal = true; } _CSP.Add(new ConsentSecurityPolicy("script-src", "'unsafe-eval'")); // Needed by Vue if (!string.IsNullOrEmpty(model.CustomCSSLink) && Uri.TryCreate(model.CustomCSSLink, UriKind.Absolute, out var uri)) { _CSP.Clear(); } if (!string.IsNullOrEmpty(model.CustomLogoLink) && Uri.TryCreate(model.CustomLogoLink, UriKind.Absolute, out uri)) { _CSP.Clear(); } return(View(nameof(Checkout), model)); }
#pragma warning disable CS0618 public static PaymentMethodId GetDefaultPaymentId(this StoreData storeData, BTCPayNetworkProvider networks) { PaymentMethodId[] paymentMethodIds = storeData.GetEnabledPaymentIds(networks); var defaultPaymentId = string.IsNullOrEmpty(storeData.DefaultCrypto) ? null : PaymentMethodId.Parse(storeData.DefaultCrypto); var chosen = paymentMethodIds.FirstOrDefault(f => f == defaultPaymentId) ?? paymentMethodIds.FirstOrDefault(f => f.CryptoCode == defaultPaymentId?.CryptoCode) ?? paymentMethodIds.FirstOrDefault(); return(chosen); }
public async Task <IActionResult> CheckoutExperience(CheckoutExperienceViewModel model) { bool needUpdate = false; var blob = CurrentStore.GetStoreBlob(); var defaultPaymentMethodId = model.DefaultPaymentMethod == null ? null : PaymentMethodId.Parse(model.DefaultPaymentMethod); if (CurrentStore.GetDefaultPaymentId(_NetworkProvider) != defaultPaymentMethodId) { needUpdate = true; CurrentStore.SetDefaultPaymentId(defaultPaymentMethodId); } SetCryptoCurrencies(model, CurrentStore); model.SetLanguages(_LangService, model.DefaultLang); model.PaymentMethodCriteria ??= new List <PaymentMethodCriteriaViewModel>(); for (var index = 0; index < model.PaymentMethodCriteria.Count; index++) { var methodCriterion = model.PaymentMethodCriteria[index]; if (!string.IsNullOrWhiteSpace(methodCriterion.Value)) { if (!CurrencyValue.TryParse(methodCriterion.Value, out var value)) { model.AddModelError(viewModel => viewModel.PaymentMethodCriteria[index].Value, $"{methodCriterion.PaymentMethod}: invalid format (1.0 USD)", this); } } } if (!ModelState.IsValid) { return(View(model)); } blob.PaymentMethodCriteria = model.PaymentMethodCriteria .Where(viewModel => !string.IsNullOrEmpty(viewModel.Value)).Select(viewModel => { CurrencyValue.TryParse(viewModel.Value, out var cv); return(new PaymentMethodCriteria() { Above = viewModel.Type == PaymentMethodCriteriaViewModel.CriteriaType.GreaterThan, Value = cv, PaymentMethod = PaymentMethodId.Parse(viewModel.PaymentMethod) }); }).ToList(); blob.RequiresRefundEmail = model.RequiresRefundEmail; blob.LightningAmountInSatoshi = model.LightningAmountInSatoshi; blob.LightningPrivateRouteHints = model.LightningPrivateRouteHints; blob.OnChainWithLnInvoiceFallback = model.OnChainWithLnInvoiceFallback; blob.RedirectAutomatically = model.RedirectAutomatically; blob.ShowRecommendedFee = model.ShowRecommendedFee; blob.RecommendedFeeBlockTarget = model.RecommendedFeeBlockTarget; blob.CustomLogo = model.CustomLogo; blob.CustomCSS = model.CustomCSS; blob.HtmlTitle = string.IsNullOrWhiteSpace(model.HtmlTitle) ? null : model.HtmlTitle; blob.DefaultLang = model.DefaultLang; if (CurrentStore.SetStoreBlob(blob)) { needUpdate = true; } if (needUpdate) { await _Repo.UpdateStore(CurrentStore); TempData[WellKnownTempData.SuccessMessage] = "Store successfully updated"; } return(RedirectToAction(nameof(CheckoutExperience), new { storeId = CurrentStore.Id })); }
public IPaymentFilter GetExcludedPaymentMethods() { #pragma warning disable CS0618 // Type or member is obsolete if (ExcludedPaymentMethods == null || ExcludedPaymentMethods.Length == 0) { return(PaymentFilter.Never()); } return(PaymentFilter.Any(ExcludedPaymentMethods.Select(p => PaymentFilter.WhereIs(PaymentMethodId.Parse(p))).ToArray())); #pragma warning restore CS0618 // Type or member is obsolete }
public static PaymentMethodId GetPaymentMethodId(this PayoutData data) { return(PaymentMethodId.Parse(data.PaymentMethodId)); }