mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Make Invoice Create Faster And Fix Gap Limit Issue (#1843)
* Make Invoice Create Faster And Fix Gap Limit Issue This make address reserve only when user "activate" paymet method in ui. optional setting in store checkout ui. * Fix swagger documentation around Lazy payment methods * fix changed code signature * Add missing GreenField API for activate feature * Fix checkout experience styling for activate feature * Fix issue with Checkout activate button * Make lightning also work with activation * Make sure PreparePaymentModel is still called on payment handlers even when unactivated * Make payment link return empty if not activated * Add activate payment method method to client and add test * remove debugger * add e2e test * Rearranging lazy payments position in UI to be near dependent Unified QR code * fix rebase conflicts * Make lazy payment method mode activate on UI load. Co-authored-by: Kukks <evilkukka@gmail.com> Co-authored-by: rockstardev <rockstardev@users.noreply.github.com> Co-authored-by: Andrew Camilleri <kukks@btcpayserver.org>
This commit is contained in:
@@ -85,5 +85,13 @@ namespace BTCPayServer.Client
|
|||||||
method: HttpMethod.Post), token);
|
method: HttpMethod.Post), token);
|
||||||
return await HandleResponse<InvoiceData>(response);
|
return await HandleResponse<InvoiceData>(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual async Task ActivateInvoicePaymentMethod(string storeId, string invoiceId, string paymentMethod, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var response = await _httpClient.SendAsync(
|
||||||
|
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods/{paymentMethod}/activate",
|
||||||
|
method: HttpMethod.Post), token);
|
||||||
|
await HandleResponse(response);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace BTCPayServer.Client.Models
|
|||||||
{
|
{
|
||||||
public class InvoicePaymentMethodDataModel
|
public class InvoicePaymentMethodDataModel
|
||||||
{
|
{
|
||||||
|
public bool Activated { get; set; }
|
||||||
public string Destination { get; set; }
|
public string Destination { get; set; }
|
||||||
public string PaymentLink { get; set; }
|
public string PaymentLink { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace BTCPayServer.Client.Models
|
|||||||
public bool LightningAmountInSatoshi { get; set; }
|
public bool LightningAmountInSatoshi { get; set; }
|
||||||
public bool LightningPrivateRouteHints { get; set; }
|
public bool LightningPrivateRouteHints { get; set; }
|
||||||
public bool OnChainWithLnInvoiceFallback { get; set; }
|
public bool OnChainWithLnInvoiceFallback { get; set; }
|
||||||
|
public bool LazyPaymentMethods { get; set; }
|
||||||
public bool RedirectAutomatically { get; set; }
|
public bool RedirectAutomatically { get; set; }
|
||||||
|
|
||||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||||
@@ -53,8 +54,6 @@ namespace BTCPayServer.Client.Models
|
|||||||
|
|
||||||
public string HtmlTitle { get; set; }
|
public string HtmlTitle { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public NetworkFeeMode NetworkFeeMode { get; set; } = NetworkFeeMode.Never;
|
public NetworkFeeMode NetworkFeeMode { get; set; } = NetworkFeeMode.Never;
|
||||||
|
|||||||
@@ -1093,6 +1093,24 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
Assert.Equal("pt-PT", langs.FindBestMatch(match).Code);
|
Assert.Equal("pt-PT", langs.FindBestMatch(match).Code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//payment method activation tests
|
||||||
|
var store = await client.GetStore(user.StoreId);
|
||||||
|
Assert.False(store.LazyPaymentMethods);
|
||||||
|
store.LazyPaymentMethods = true;
|
||||||
|
store = await client.UpdateStore(store.Id,
|
||||||
|
JObject.FromObject(store).ToObject<UpdateStoreRequest>());
|
||||||
|
Assert.True(store.LazyPaymentMethods);
|
||||||
|
|
||||||
|
invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest() {Amount = 1, Currency = "USD"});
|
||||||
|
paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id);
|
||||||
|
Assert.Single(paymentMethods);
|
||||||
|
Assert.False(paymentMethods.First().Activated);
|
||||||
|
await client.ActivateInvoicePaymentMethod(user.StoreId, invoice.Id,
|
||||||
|
paymentMethods.First().PaymentMethod);
|
||||||
|
paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id);
|
||||||
|
Assert.Single(paymentMethods);
|
||||||
|
Assert.True(paymentMethods.First().Activated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using BTCPayServer.Services.Wallets;
|
|||||||
using BTCPayServer.Tests.Logging;
|
using BTCPayServer.Tests.Logging;
|
||||||
using BTCPayServer.Views.Manage;
|
using BTCPayServer.Views.Manage;
|
||||||
using BTCPayServer.Views.Server;
|
using BTCPayServer.Views.Server;
|
||||||
|
using BTCPayServer.Views.Stores;
|
||||||
using BTCPayServer.Views.Wallets;
|
using BTCPayServer.Views.Wallets;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|||||||
@@ -25,14 +25,22 @@ namespace BTCPayServer.Controllers.GreenField
|
|||||||
private readonly InvoiceController _invoiceController;
|
private readonly InvoiceController _invoiceController;
|
||||||
private readonly InvoiceRepository _invoiceRepository;
|
private readonly InvoiceRepository _invoiceRepository;
|
||||||
private readonly LinkGenerator _linkGenerator;
|
private readonly LinkGenerator _linkGenerator;
|
||||||
|
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
||||||
|
private readonly EventAggregator _eventAggregator;
|
||||||
|
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||||
|
|
||||||
public LanguageService LanguageService { get; }
|
public LanguageService LanguageService { get; }
|
||||||
|
|
||||||
public GreenFieldInvoiceController(InvoiceController invoiceController, InvoiceRepository invoiceRepository, LinkGenerator linkGenerator, LanguageService languageService)
|
public GreenFieldInvoiceController(InvoiceController invoiceController, InvoiceRepository invoiceRepository,
|
||||||
|
LinkGenerator linkGenerator, LanguageService languageService, BTCPayNetworkProvider btcPayNetworkProvider,
|
||||||
|
EventAggregator eventAggregator, PaymentMethodHandlerDictionary paymentMethodHandlerDictionary)
|
||||||
{
|
{
|
||||||
_invoiceController = invoiceController;
|
_invoiceController = invoiceController;
|
||||||
_invoiceRepository = invoiceRepository;
|
_invoiceRepository = invoiceRepository;
|
||||||
_linkGenerator = linkGenerator;
|
_linkGenerator = linkGenerator;
|
||||||
|
_btcPayNetworkProvider = btcPayNetworkProvider;
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
_paymentMethodHandlerDictionary = paymentMethodHandlerDictionary;
|
||||||
LanguageService = languageService;
|
LanguageService = languageService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +276,32 @@ namespace BTCPayServer.Controllers.GreenField
|
|||||||
|
|
||||||
return Ok(ToPaymentMethodModels(invoice));
|
return Ok(ToPaymentMethodModels(invoice));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = Policies.CanViewInvoices,
|
||||||
|
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
|
[HttpPost("~/api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods/{paymentMethod}/activate")]
|
||||||
|
public async Task<IActionResult> ActivateInvoicePaymentMethod(string storeId, string invoiceId, string paymentMethod)
|
||||||
|
{
|
||||||
|
var store = HttpContext.GetStoreData();
|
||||||
|
if (store == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var invoice = await _invoiceRepository.GetInvoice(invoiceId, true);
|
||||||
|
if (invoice?.StoreId != store.Id)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PaymentMethodId.TryParse(paymentMethod, out var paymentMethodId))
|
||||||
|
{
|
||||||
|
await _invoiceRepository.ActivateInvoicePaymentMethod(_eventAggregator, _btcPayNetworkProvider,
|
||||||
|
_paymentMethodHandlerDictionary, store, invoice, paymentMethodId);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
private InvoicePaymentMethodDataModel[] ToPaymentMethodModels(InvoiceEntity entity)
|
private InvoicePaymentMethodDataModel[] ToPaymentMethodModels(InvoiceEntity entity)
|
||||||
{
|
{
|
||||||
@@ -281,6 +315,7 @@ namespace BTCPayServer.Controllers.GreenField
|
|||||||
|
|
||||||
return new InvoicePaymentMethodDataModel()
|
return new InvoicePaymentMethodDataModel()
|
||||||
{
|
{
|
||||||
|
Activated = details.Activated,
|
||||||
PaymentMethod = method.GetId().ToStringNormalized(),
|
PaymentMethod = method.GetId().ToStringNormalized(),
|
||||||
Destination = details.GetPaymentDestination(),
|
Destination = details.GetPaymentDestination(),
|
||||||
Rate = method.Rate,
|
Rate = method.Rate,
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ namespace BTCPayServer.Controllers.GreenField
|
|||||||
LightningPrivateRouteHints = storeBlob.LightningPrivateRouteHints,
|
LightningPrivateRouteHints = storeBlob.LightningPrivateRouteHints,
|
||||||
OnChainWithLnInvoiceFallback = storeBlob.OnChainWithLnInvoiceFallback,
|
OnChainWithLnInvoiceFallback = storeBlob.OnChainWithLnInvoiceFallback,
|
||||||
RedirectAutomatically = storeBlob.RedirectAutomatically,
|
RedirectAutomatically = storeBlob.RedirectAutomatically,
|
||||||
|
LazyPaymentMethods = storeBlob.LazyPaymentMethods,
|
||||||
ShowRecommendedFee = storeBlob.ShowRecommendedFee,
|
ShowRecommendedFee = storeBlob.ShowRecommendedFee,
|
||||||
RecommendedFeeBlockTarget = storeBlob.RecommendedFeeBlockTarget,
|
RecommendedFeeBlockTarget = storeBlob.RecommendedFeeBlockTarget,
|
||||||
DefaultLang = storeBlob.DefaultLang,
|
DefaultLang = storeBlob.DefaultLang,
|
||||||
@@ -167,6 +168,7 @@ namespace BTCPayServer.Controllers.GreenField
|
|||||||
blob.LightningAmountInSatoshi = restModel.LightningAmountInSatoshi;
|
blob.LightningAmountInSatoshi = restModel.LightningAmountInSatoshi;
|
||||||
blob.LightningPrivateRouteHints = restModel.LightningPrivateRouteHints;
|
blob.LightningPrivateRouteHints = restModel.LightningPrivateRouteHints;
|
||||||
blob.OnChainWithLnInvoiceFallback = restModel.OnChainWithLnInvoiceFallback;
|
blob.OnChainWithLnInvoiceFallback = restModel.OnChainWithLnInvoiceFallback;
|
||||||
|
blob.LazyPaymentMethods = restModel.LazyPaymentMethods;
|
||||||
blob.RedirectAutomatically = restModel.RedirectAutomatically;
|
blob.RedirectAutomatically = restModel.RedirectAutomatically;
|
||||||
blob.ShowRecommendedFee = restModel.ShowRecommendedFee;
|
blob.ShowRecommendedFee = restModel.ShowRecommendedFee;
|
||||||
blob.RecommendedFeeBlockTarget = restModel.RecommendedFeeBlockTarget;
|
blob.RecommendedFeeBlockTarget = restModel.RecommendedFeeBlockTarget;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using BTCPayServer.Client.Models;
|
|||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Events;
|
using BTCPayServer.Events;
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
|
using BTCPayServer.Logging;
|
||||||
using BTCPayServer.HostedServices;
|
using BTCPayServer.HostedServices;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Models.InvoicingModels;
|
using BTCPayServer.Models.InvoicingModels;
|
||||||
@@ -503,9 +504,9 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
if (!isDefaultPaymentId)
|
if (!isDefaultPaymentId)
|
||||||
return null;
|
return null;
|
||||||
var paymentMethodTemp = invoice.GetPaymentMethods()
|
var paymentMethodTemp = invoice
|
||||||
.Where(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode)
|
.GetPaymentMethods()
|
||||||
.FirstOrDefault();
|
.FirstOrDefault(c => paymentMethodId.CryptoCode == c.GetId().CryptoCode);
|
||||||
if (paymentMethodTemp == null)
|
if (paymentMethodTemp == null)
|
||||||
paymentMethodTemp = invoice.GetPaymentMethods().First();
|
paymentMethodTemp = invoice.GetPaymentMethods().First();
|
||||||
network = paymentMethodTemp.Network;
|
network = paymentMethodTemp.Network;
|
||||||
@@ -514,6 +515,12 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
var paymentMethod = invoice.GetPaymentMethod(paymentMethodId);
|
var paymentMethod = invoice.GetPaymentMethod(paymentMethodId);
|
||||||
var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails();
|
var paymentMethodDetails = paymentMethod.GetPaymentMethodDetails();
|
||||||
|
if (!paymentMethodDetails.Activated)
|
||||||
|
{
|
||||||
|
await _InvoiceRepository.ActivateInvoicePaymentMethod(_EventAggregator, _NetworkProvider,
|
||||||
|
_paymentMethodHandlerDictionary, store, invoice, paymentMethod.GetId());
|
||||||
|
return await GetInvoiceModel(invoiceId, paymentMethodId, lang);
|
||||||
|
}
|
||||||
var dto = invoice.EntityToDTO();
|
var dto = invoice.EntityToDTO();
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
var accounting = paymentMethod.Calculate();
|
var accounting = paymentMethod.Calculate();
|
||||||
@@ -529,6 +536,7 @@ namespace BTCPayServer.Controllers
|
|||||||
var divisibility = _CurrencyNameTable.GetNumberFormatInfo(paymentMethod.GetId().CryptoCode, false)?.CurrencyDecimalDigits;
|
var divisibility = _CurrencyNameTable.GetNumberFormatInfo(paymentMethod.GetId().CryptoCode, false)?.CurrencyDecimalDigits;
|
||||||
var model = new PaymentModel()
|
var model = new PaymentModel()
|
||||||
{
|
{
|
||||||
|
Activated = paymentMethodDetails.Activated,
|
||||||
CryptoCode = network.CryptoCode,
|
CryptoCode = network.CryptoCode,
|
||||||
RootPath = this.Request.PathBase.Value.WithTrailingSlash(),
|
RootPath = this.Request.PathBase.Value.WithTrailingSlash(),
|
||||||
OrderId = invoice.Metadata.OrderId,
|
OrderId = invoice.Metadata.OrderId,
|
||||||
|
|||||||
@@ -44,12 +44,10 @@ namespace BTCPayServer.Controllers
|
|||||||
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
private readonly PaymentMethodHandlerDictionary _paymentMethodHandlerDictionary;
|
||||||
private readonly ApplicationDbContextFactory _dbContextFactory;
|
private readonly ApplicationDbContextFactory _dbContextFactory;
|
||||||
private readonly PullPaymentHostedService _paymentHostedService;
|
private readonly PullPaymentHostedService _paymentHostedService;
|
||||||
readonly IServiceProvider _ServiceProvider;
|
|
||||||
|
|
||||||
public WebhookNotificationManager WebhookNotificationManager { get; }
|
public WebhookNotificationManager WebhookNotificationManager { get; }
|
||||||
|
|
||||||
public InvoiceController(
|
public InvoiceController(
|
||||||
IServiceProvider serviceProvider,
|
|
||||||
InvoiceRepository invoiceRepository,
|
InvoiceRepository invoiceRepository,
|
||||||
CurrencyNameTable currencyNameTable,
|
CurrencyNameTable currencyNameTable,
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
@@ -63,7 +61,6 @@ namespace BTCPayServer.Controllers
|
|||||||
PullPaymentHostedService paymentHostedService,
|
PullPaymentHostedService paymentHostedService,
|
||||||
WebhookNotificationManager webhookNotificationManager)
|
WebhookNotificationManager webhookNotificationManager)
|
||||||
{
|
{
|
||||||
_ServiceProvider = serviceProvider;
|
|
||||||
_CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable));
|
_CurrencyNameTable = currencyNameTable ?? throw new ArgumentNullException(nameof(currencyNameTable));
|
||||||
_StoreRepository = storeRepository ?? throw new ArgumentNullException(nameof(storeRepository));
|
_StoreRepository = storeRepository ?? throw new ArgumentNullException(nameof(storeRepository));
|
||||||
_InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
|
_InvoiceRepository = invoiceRepository ?? throw new ArgumentNullException(nameof(invoiceRepository));
|
||||||
@@ -321,7 +318,16 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
var logPrefix = $"{supportedPaymentMethod.PaymentId.ToPrettyString()}:";
|
var logPrefix = $"{supportedPaymentMethod.PaymentId.ToPrettyString()}:";
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
var preparePayment = handler.PreparePayment(supportedPaymentMethod, store, network);
|
|
||||||
|
object preparePayment;
|
||||||
|
if (storeBlob.LazyPaymentMethods)
|
||||||
|
{
|
||||||
|
preparePayment = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
preparePayment = handler.PreparePayment(supportedPaymentMethod, store, network);
|
||||||
|
}
|
||||||
var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.Currency)];
|
var rate = await fetchingByCurrencyPair[new CurrencyPair(network.CryptoCode, entity.Currency)];
|
||||||
if (rate.BidAsk == null)
|
if (rate.BidAsk == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -406,6 +406,7 @@ namespace BTCPayServer.Controllers
|
|||||||
vm.LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi;
|
vm.LightningAmountInSatoshi = storeBlob.LightningAmountInSatoshi;
|
||||||
vm.LightningPrivateRouteHints = storeBlob.LightningPrivateRouteHints;
|
vm.LightningPrivateRouteHints = storeBlob.LightningPrivateRouteHints;
|
||||||
vm.OnChainWithLnInvoiceFallback = storeBlob.OnChainWithLnInvoiceFallback;
|
vm.OnChainWithLnInvoiceFallback = storeBlob.OnChainWithLnInvoiceFallback;
|
||||||
|
vm.LazyPaymentMethods = storeBlob.LazyPaymentMethods;
|
||||||
vm.RedirectAutomatically = storeBlob.RedirectAutomatically;
|
vm.RedirectAutomatically = storeBlob.RedirectAutomatically;
|
||||||
vm.ShowRecommendedFee = storeBlob.ShowRecommendedFee;
|
vm.ShowRecommendedFee = storeBlob.ShowRecommendedFee;
|
||||||
vm.RecommendedFeeBlockTarget = storeBlob.RecommendedFeeBlockTarget;
|
vm.RecommendedFeeBlockTarget = storeBlob.RecommendedFeeBlockTarget;
|
||||||
@@ -477,6 +478,7 @@ namespace BTCPayServer.Controllers
|
|||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
blob.RequiresRefundEmail = model.RequiresRefundEmail;
|
blob.RequiresRefundEmail = model.RequiresRefundEmail;
|
||||||
|
blob.LazyPaymentMethods = model.LazyPaymentMethods;
|
||||||
blob.LightningAmountInSatoshi = model.LightningAmountInSatoshi;
|
blob.LightningAmountInSatoshi = model.LightningAmountInSatoshi;
|
||||||
blob.LightningPrivateRouteHints = model.LightningPrivateRouteHints;
|
blob.LightningPrivateRouteHints = model.LightningPrivateRouteHints;
|
||||||
blob.OnChainWithLnInvoiceFallback = model.OnChainWithLnInvoiceFallback;
|
blob.OnChainWithLnInvoiceFallback = model.OnChainWithLnInvoiceFallback;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace BTCPayServer.Data
|
|||||||
public bool LightningAmountInSatoshi { get; set; }
|
public bool LightningAmountInSatoshi { get; set; }
|
||||||
public bool LightningPrivateRouteHints { get; set; }
|
public bool LightningPrivateRouteHints { get; set; }
|
||||||
public bool OnChainWithLnInvoiceFallback { get; set; }
|
public bool OnChainWithLnInvoiceFallback { get; set; }
|
||||||
|
public bool LazyPaymentMethods { get; set; }
|
||||||
public bool RedirectAutomatically { get; set; }
|
public bool RedirectAutomatically { get; set; }
|
||||||
public bool ShowRecommendedFee { get; set; }
|
public bool ShowRecommendedFee { get; set; }
|
||||||
public int RecommendedFeeBlockTarget { get; set; }
|
public int RecommendedFeeBlockTarget { get; set; }
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ namespace BTCPayServer.HostedServices
|
|||||||
|
|
||||||
// We keep backward compatibility with bitpay by passing BTC info to the notification
|
// We keep backward compatibility with bitpay by passing BTC info to the notification
|
||||||
// we don't pass other info, as it is a bad idea to use IPN data for logic processing (can be faked)
|
// we don't pass other info, as it is a bad idea to use IPN data for logic processing (can be faked)
|
||||||
var btcCryptoInfo = dto.CryptoInfo.FirstOrDefault(c => c.GetpaymentMethodId() == new PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike));
|
var btcCryptoInfo = dto.CryptoInfo.FirstOrDefault(c => c.GetpaymentMethodId() == new PaymentMethodId("BTC", Payments.PaymentTypes.BTCLike) && !string.IsNullOrEmpty(c.Address));
|
||||||
if (btcCryptoInfo != null)
|
if (btcCryptoInfo != null)
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0618
|
#pragma warning disable CS0618
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ namespace BTCPayServer.Models.InvoicingModels
|
|||||||
public string RootPath { get; set; }
|
public string RootPath { get; set; }
|
||||||
public decimal CoinSwitchAmountMarkupPercentage { get; set; }
|
public decimal CoinSwitchAmountMarkupPercentage { get; set; }
|
||||||
public bool RedirectAutomatically { get; set; }
|
public bool RedirectAutomatically { get; set; }
|
||||||
|
public bool Activated { get; set; }
|
||||||
public string InvoiceCurrency { get; set; }
|
public string InvoiceCurrency { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using BTCPayServer.Data;
|
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||||
@@ -45,6 +44,9 @@ namespace BTCPayServer.Models.StoreViewModels
|
|||||||
[Display(Name = "Include lightning invoice fallback to on-chain BIP21 payment url")]
|
[Display(Name = "Include lightning invoice fallback to on-chain BIP21 payment url")]
|
||||||
public bool OnChainWithLnInvoiceFallback { get; set; }
|
public bool OnChainWithLnInvoiceFallback { get; set; }
|
||||||
|
|
||||||
|
[Display(Name = "Only enable the payment method after user explicitly chooses it")]
|
||||||
|
public bool LazyPaymentMethods { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Redirect invoice to redirect url automatically after paid")]
|
[Display(Name = "Redirect invoice to redirect url automatically after paid")]
|
||||||
public bool RedirectAutomatically { get; set; }
|
public bool RedirectAutomatically { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
|
|
||||||
public decimal GetFeeRate()
|
public decimal GetFeeRate()
|
||||||
{
|
{
|
||||||
return FeeRate.SatoshiPerByte;
|
return FeeRate?.SatoshiPerByte ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPaymentDetails(IPaymentMethodDetails newPaymentMethodDetails)
|
public void SetPaymentDetails(IPaymentMethodDetails newPaymentMethodDetails)
|
||||||
@@ -31,6 +31,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
DepositAddress = newPaymentMethodDetails.GetPaymentDestination();
|
DepositAddress = newPaymentMethodDetails.GetPaymentDestination();
|
||||||
KeyPath = (newPaymentMethodDetails as BitcoinLikeOnChainPaymentMethod)?.KeyPath;
|
KeyPath = (newPaymentMethodDetails as BitcoinLikeOnChainPaymentMethod)?.KeyPath;
|
||||||
}
|
}
|
||||||
|
public bool Activated { get; set; } = true;
|
||||||
public NetworkFeeMode NetworkFeeMode { get; set; }
|
public NetworkFeeMode NetworkFeeMode { get; set; }
|
||||||
|
|
||||||
FeeRate _NetworkFeeRate;
|
FeeRate _NetworkFeeRate;
|
||||||
|
|||||||
@@ -64,16 +64,24 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
model.PaymentMethodName = GetPaymentMethodName(network);
|
model.PaymentMethodName = GetPaymentMethodName(network);
|
||||||
|
|
||||||
var lightningFallback = "";
|
var lightningFallback = "";
|
||||||
if (network.SupportLightning && storeBlob.OnChainWithLnInvoiceFallback)
|
if (model.Activated && network.SupportLightning && storeBlob.OnChainWithLnInvoiceFallback)
|
||||||
{
|
{
|
||||||
var lightningInfo = invoiceResponse.CryptoInfo.FirstOrDefault(a =>
|
var lightningInfo = invoiceResponse.CryptoInfo.FirstOrDefault(a =>
|
||||||
a.GetpaymentMethodId() == new PaymentMethodId(model.CryptoCode, PaymentTypes.LightningLike));
|
a.GetpaymentMethodId() == new PaymentMethodId(model.CryptoCode, PaymentTypes.LightningLike));
|
||||||
if (!String.IsNullOrEmpty(lightningInfo?.PaymentUrls?.BOLT11))
|
if (!string.IsNullOrEmpty(lightningInfo?.PaymentUrls?.BOLT11))
|
||||||
lightningFallback = "&" + lightningInfo.PaymentUrls.BOLT11.Replace("lightning:", "lightning=", StringComparison.OrdinalIgnoreCase);
|
lightningFallback = "&" + lightningInfo.PaymentUrls.BOLT11.Replace("lightning:", "lightning=", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
model.InvoiceBitcoinUrl = cryptoInfo.PaymentUrls.BIP21 + lightningFallback;
|
if (model.Activated)
|
||||||
model.InvoiceBitcoinUrlQR = model.InvoiceBitcoinUrl;
|
{
|
||||||
|
model.InvoiceBitcoinUrl = (cryptoInfo.PaymentUrls?.BIP21 ?? "") + lightningFallback;
|
||||||
|
model.InvoiceBitcoinUrlQR = model.InvoiceBitcoinUrl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
model.InvoiceBitcoinUrl = "";
|
||||||
|
model.InvoiceBitcoinUrlQR = "";
|
||||||
|
}
|
||||||
|
|
||||||
// Most wallets still don't support BITCOIN: schema, so we're leaving this for better days
|
// Most wallets still don't support BITCOIN: schema, so we're leaving this for better days
|
||||||
// Ref: https://github.com/btcpayserver/btcpayserver/pull/2060#issuecomment-723828348
|
// Ref: https://github.com/btcpayserver/btcpayserver/pull/2060#issuecomment-723828348
|
||||||
@@ -145,12 +153,19 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
DerivationSchemeSettings supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store,
|
DerivationSchemeSettings supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store,
|
||||||
BTCPayNetwork network, object preparePaymentObject)
|
BTCPayNetwork network, object preparePaymentObject)
|
||||||
{
|
{
|
||||||
|
if (preparePaymentObject is null)
|
||||||
|
{
|
||||||
|
return new BitcoinLikeOnChainPaymentMethod()
|
||||||
|
{
|
||||||
|
Activated = false
|
||||||
|
};
|
||||||
|
}
|
||||||
if (!_ExplorerProvider.IsAvailable(network))
|
if (!_ExplorerProvider.IsAvailable(network))
|
||||||
throw new PaymentMethodUnavailableException($"Full node not available");
|
throw new PaymentMethodUnavailableException($"Full node not available");
|
||||||
var prepare = (Prepare)preparePaymentObject;
|
var prepare = (Prepare)preparePaymentObject;
|
||||||
var onchainMethod = new BitcoinLikeOnChainPaymentMethod();
|
var onchainMethod = new BitcoinLikeOnChainPaymentMethod();
|
||||||
var blob = store.GetStoreBlob();
|
var blob = store.GetStoreBlob();
|
||||||
|
onchainMethod.Activated = true;
|
||||||
// TODO: this needs to be refactored to move this logic into BitcoinLikeOnChainPaymentMethod
|
// TODO: this needs to be refactored to move this logic into BitcoinLikeOnChainPaymentMethod
|
||||||
// This is likely a constructor code
|
// This is likely a constructor code
|
||||||
onchainMethod.NetworkFeeMode = blob.NetworkFeeMode;
|
onchainMethod.NetworkFeeMode = blob.NetworkFeeMode;
|
||||||
|
|||||||
@@ -352,7 +352,6 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
if (strategy == null)
|
if (strategy == null)
|
||||||
continue;
|
continue;
|
||||||
var cryptoId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
|
var cryptoId = new PaymentMethodId(network.CryptoCode, PaymentTypes.BTCLike);
|
||||||
var paymentMethod = invoice.GetPaymentMethod(cryptoId).GetPaymentMethodDetails() as BitcoinLikeOnChainPaymentMethod;
|
|
||||||
|
|
||||||
if (!invoice.Support(cryptoId))
|
if (!invoice.Support(cryptoId))
|
||||||
continue;
|
continue;
|
||||||
@@ -403,6 +402,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
|||||||
var paymentMethod = invoice.GetPaymentMethod(wallet.Network, PaymentTypes.BTCLike);
|
var paymentMethod = invoice.GetPaymentMethod(wallet.Network, PaymentTypes.BTCLike);
|
||||||
if (paymentMethod != null &&
|
if (paymentMethod != null &&
|
||||||
paymentMethod.GetPaymentMethodDetails() is BitcoinLikeOnChainPaymentMethod btc &&
|
paymentMethod.GetPaymentMethodDetails() is BitcoinLikeOnChainPaymentMethod btc &&
|
||||||
|
btc.Activated &&
|
||||||
btc.GetDepositAddress(wallet.Network.NBitcoinNetwork).ScriptPubKey == paymentData.ScriptPubKey &&
|
btc.GetDepositAddress(wallet.Network.NBitcoinNetwork).ScriptPubKey == paymentData.ScriptPubKey &&
|
||||||
paymentMethod.Calculate().Due > Money.Zero)
|
paymentMethod.Calculate().Due > Money.Zero)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,5 +16,7 @@ namespace BTCPayServer.Payments
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
decimal GetNextNetworkFee();
|
decimal GetNextNetworkFee();
|
||||||
|
|
||||||
|
bool Activated {get;set;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store,
|
LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store,
|
||||||
BTCPayNetwork network, object preparePaymentObject)
|
BTCPayNetwork network, object preparePaymentObject)
|
||||||
{
|
{
|
||||||
|
if (preparePaymentObject is null)
|
||||||
|
{
|
||||||
|
return new LightningLikePaymentMethodDetails()
|
||||||
|
{
|
||||||
|
Activated = false
|
||||||
|
};
|
||||||
|
}
|
||||||
//direct casting to (BTCPayNetwork) is fixed in other pull requests with better generic interfacing for handlers
|
//direct casting to (BTCPayNetwork) is fixed in other pull requests with better generic interfacing for handlers
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
var test = GetNodeInfo(paymentMethod.PreferOnion, supportedPaymentMethod, network);
|
var test = GetNodeInfo(paymentMethod.PreferOnion, supportedPaymentMethod, network);
|
||||||
@@ -99,6 +106,7 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
var nodeInfo = await test;
|
var nodeInfo = await test;
|
||||||
return new LightningLikePaymentMethodDetails
|
return new LightningLikePaymentMethodDetails
|
||||||
{
|
{
|
||||||
|
Activated = true,
|
||||||
BOLT11 = lightningInvoice.BOLT11,
|
BOLT11 = lightningInvoice.BOLT11,
|
||||||
InvoiceId = lightningInvoice.Id,
|
InvoiceId = lightningInvoice.Id,
|
||||||
NodeInfo = nodeInfo.ToString()
|
NodeInfo = nodeInfo.ToString()
|
||||||
@@ -191,8 +199,8 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
||||||
var network = _networkProvider.GetNetwork<BTCPayNetwork>(model.CryptoCode);
|
var network = _networkProvider.GetNetwork<BTCPayNetwork>(model.CryptoCode);
|
||||||
model.PaymentMethodName = GetPaymentMethodName(network);
|
model.PaymentMethodName = GetPaymentMethodName(network);
|
||||||
model.InvoiceBitcoinUrl = cryptoInfo.PaymentUrls.BOLT11;
|
model.InvoiceBitcoinUrl = cryptoInfo.PaymentUrls?.BOLT11;
|
||||||
model.InvoiceBitcoinUrlQR = $"lightning:{cryptoInfo.PaymentUrls.BOLT11.ToUpperInvariant().Substring("LIGHTNING:".Length)}";
|
model.InvoiceBitcoinUrlQR = $"lightning:{cryptoInfo.PaymentUrls?.BOLT11?.ToUpperInvariant()?.Substring("LIGHTNING:".Length)}";
|
||||||
|
|
||||||
model.PeerInfo = ((LightningLikePaymentMethodDetails) paymentMethod.GetPaymentMethodDetails()).NodeInfo;
|
model.PeerInfo = ((LightningLikePaymentMethodDetails) paymentMethod.GetPaymentMethodDetails()).NodeInfo;
|
||||||
if (storeBlob.LightningAmountInSatoshi && model.CryptoCode == "BTC")
|
if (storeBlob.LightningAmountInSatoshi && model.CryptoCode == "BTC")
|
||||||
@@ -238,5 +246,12 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
{
|
{
|
||||||
return $"{network.DisplayName} (Lightning)";
|
return $"{network.DisplayName} (Lightning)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override object PreparePayment(LightningSupportedPaymentMethod supportedPaymentMethod, StoreData store,
|
||||||
|
BTCPayNetworkBase network)
|
||||||
|
{
|
||||||
|
// pass a non null obj, so that if lazy payment feature is used, it has a marker to trigger activation
|
||||||
|
return new { };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,5 +25,6 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
{
|
{
|
||||||
return 0.0m;
|
return 0.0m;
|
||||||
}
|
}
|
||||||
|
public bool Activated { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ namespace BTCPayServer.Payments.Lightning
|
|||||||
.Where(c => c.GetId().PaymentType == PaymentTypes.LightningLike))
|
.Where(c => c.GetId().PaymentType == PaymentTypes.LightningLike))
|
||||||
{
|
{
|
||||||
var lightningMethod = paymentMethod.GetPaymentMethodDetails() as LightningLikePaymentMethodDetails;
|
var lightningMethod = paymentMethod.GetPaymentMethodDetails() as LightningLikePaymentMethodDetails;
|
||||||
if (lightningMethod == null)
|
if (lightningMethod == null || !lightningMethod.Activated)
|
||||||
continue;
|
continue;
|
||||||
var lightningSupportedMethod = invoice.GetSupportedPaymentMethod<LightningSupportedPaymentMethod>()
|
var lightningSupportedMethod = invoice.GetSupportedPaymentMethod<LightningSupportedPaymentMethod>()
|
||||||
.FirstOrDefault(c => c.CryptoCode == paymentMethod.GetId().CryptoCode);
|
.FirstOrDefault(c => c.CryptoCode == paymentMethod.GetId().CryptoCode);
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ namespace BTCPayServer.Payments.PayJoin
|
|||||||
var paymentMethod = invoice.GetPaymentMethod(paymentMethodId);
|
var paymentMethod = invoice.GetPaymentMethod(paymentMethodId);
|
||||||
var paymentDetails =
|
var paymentDetails =
|
||||||
paymentMethod.GetPaymentMethodDetails() as Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod;
|
paymentMethod.GetPaymentMethodDetails() as Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod;
|
||||||
if (paymentDetails is null || !paymentDetails.PayjoinEnabled)
|
if (paymentDetails is null || !paymentDetails.PayjoinEnabled || !paymentDetails.Activated)
|
||||||
continue;
|
continue;
|
||||||
if (invoice.GetAllBitcoinPaymentData().Any())
|
if (invoice.GetAllBitcoinPaymentData().Any())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ namespace BTCPayServer.Payments
|
|||||||
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails,
|
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails,
|
||||||
Money cryptoInfoDue, string serverUri)
|
Money cryptoInfoDue, string serverUri)
|
||||||
{
|
{
|
||||||
|
if (!paymentMethodDetails.Activated)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
var bip21 = ((BTCPayNetwork)network).GenerateBIP21(paymentMethodDetails.GetPaymentDestination(), cryptoInfoDue);
|
var bip21 = ((BTCPayNetwork)network).GenerateBIP21(paymentMethodDetails.GetPaymentDestination(), cryptoInfoDue);
|
||||||
|
|
||||||
if ((paymentMethodDetails as BitcoinLikeOnChainPaymentMethod)?.PayjoinEnabled is true && serverUri != null)
|
if ((paymentMethodDetails as BitcoinLikeOnChainPaymentMethod)?.PayjoinEnabled is true && serverUri != null)
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ namespace BTCPayServer.Payments
|
|||||||
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails,
|
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails,
|
||||||
Money cryptoInfoDue, string serverUri)
|
Money cryptoInfoDue, string serverUri)
|
||||||
{
|
{
|
||||||
|
if (!paymentMethodDetails.Activated)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
var lnInvoiceTrimmedOfScheme = paymentMethodDetails.GetPaymentDestination().ToLowerInvariant()
|
var lnInvoiceTrimmedOfScheme = paymentMethodDetails.GetPaymentDestination().ToLowerInvariant()
|
||||||
.Replace("lightning:", "", StringComparison.InvariantCultureIgnoreCase);
|
.Replace("lightning:", "", StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ namespace BTCPayServer.Services.Altcoins.Ethereum.Payments
|
|||||||
{
|
{
|
||||||
DepositAddress = newPaymentDestination;
|
DepositAddress = newPaymentDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Activated { get; set; }
|
||||||
public long Index { get; set; }
|
public long Index { get; set; }
|
||||||
public string XPub { get; set; }
|
public string XPub { get; set; }
|
||||||
public string DepositAddress { get; set; }
|
public string DepositAddress { get; set; }
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ namespace BTCPayServer.Services.Altcoins.Ethereum.Payments
|
|||||||
EthereumSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod,
|
EthereumSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod,
|
||||||
StoreData store, EthereumBTCPayNetwork network, object preparePaymentObject)
|
StoreData store, EthereumBTCPayNetwork network, object preparePaymentObject)
|
||||||
{
|
{
|
||||||
|
if (preparePaymentObject is null)
|
||||||
|
{
|
||||||
|
return new EthereumLikeOnChainPaymentMethodDetails()
|
||||||
|
{
|
||||||
|
Activated = false
|
||||||
|
};
|
||||||
|
}
|
||||||
if (!_ethereumService.IsAvailable(network.CryptoCode, out var error))
|
if (!_ethereumService.IsAvailable(network.CryptoCode, out var error))
|
||||||
throw new PaymentMethodUnavailableException(error??$"Not configured yet");
|
throw new PaymentMethodUnavailableException(error??$"Not configured yet");
|
||||||
var invoice = paymentMethod.ParentEntity;
|
var invoice = paymentMethod.ParentEntity;
|
||||||
@@ -47,7 +54,7 @@ namespace BTCPayServer.Services.Altcoins.Ethereum.Payments
|
|||||||
|
|
||||||
return new EthereumLikeOnChainPaymentMethodDetails()
|
return new EthereumLikeOnChainPaymentMethodDetails()
|
||||||
{
|
{
|
||||||
DepositAddress = address.Address, Index = address.Index, XPub = address.XPub
|
DepositAddress = address.Address, Index = address.Index, XPub = address.XPub, Activated = true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +86,7 @@ namespace BTCPayServer.Services.Altcoins.Ethereum.Payments
|
|||||||
model.PaymentMethodName = GetPaymentMethodName(network);
|
model.PaymentMethodName = GetPaymentMethodName(network);
|
||||||
model.CryptoImage = GetCryptoImage(network);
|
model.CryptoImage = GetCryptoImage(network);
|
||||||
model.InvoiceBitcoinUrl = "";
|
model.InvoiceBitcoinUrl = "";
|
||||||
model.InvoiceBitcoinUrlQR = cryptoInfo.Address;
|
model.InvoiceBitcoinUrlQR = cryptoInfo.Address ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetCryptoImage(PaymentMethodId paymentMethodId)
|
public override string GetCryptoImage(PaymentMethodId paymentMethodId)
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ namespace BTCPayServer.Services.Altcoins.Ethereum.Services
|
|||||||
|
|
||||||
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() {InvoiceId = invoiceIds});
|
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() {InvoiceId = invoiceIds});
|
||||||
invoices = invoices
|
invoices = invoices
|
||||||
.Where(entity => PaymentMethods.Any(id => entity.GetPaymentMethod(id) != null))
|
.Where(entity => PaymentMethods.Any(id => entity.GetPaymentMethod(id)?.GetPaymentMethodDetails()?.Activated is true))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
await UpdatePaymentStates(invoices, cancellationToken);
|
await UpdatePaymentStates(invoices, cancellationToken);
|
||||||
@@ -245,7 +245,7 @@ namespace BTCPayServer.Services.Altcoins.Ethereum.Services
|
|||||||
ExistingPayments: entity.GetPayments(network).Select(paymentEntity => (Payment: paymentEntity,
|
ExistingPayments: entity.GetPayments(network).Select(paymentEntity => (Payment: paymentEntity,
|
||||||
PaymentData: (EthereumLikePaymentData)paymentEntity.GetCryptoPaymentData(),
|
PaymentData: (EthereumLikePaymentData)paymentEntity.GetCryptoPaymentData(),
|
||||||
Invoice: entity))
|
Invoice: entity))
|
||||||
)).Where(tuple => tuple.PaymentMethodDetails != null).ToList();
|
)).Where(tuple => tuple.PaymentMethodDetails?.GetPaymentMethodDetails()?.Activated is true).ToList();
|
||||||
|
|
||||||
var existingPaymentData = expandedInvoices.SelectMany(tuple =>
|
var existingPaymentData = expandedInvoices.SelectMany(tuple =>
|
||||||
tuple.ExistingPayments.Where(valueTuple => valueTuple.Payment.Accounted)).ToList();
|
tuple.ExistingPayments.Where(valueTuple => valueTuple.Payment.Accounted)).ToList();
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
|||||||
{
|
{
|
||||||
return 0.0m;
|
return 0.0m;
|
||||||
}
|
}
|
||||||
|
public bool Activated { get; set; } = true;
|
||||||
public long AccountIndex { get; set; }
|
public long AccountIndex { get; set; }
|
||||||
public long AddressIndex { get; set; }
|
public long AddressIndex { get; set; }
|
||||||
public string DepositAddress { get; set; }
|
public string DepositAddress { get; set; }
|
||||||
|
|||||||
@@ -34,6 +34,14 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
|||||||
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, MoneroSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod,
|
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, MoneroSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod,
|
||||||
StoreData store, MoneroLikeSpecificBtcPayNetwork network, object preparePaymentObject)
|
StoreData store, MoneroLikeSpecificBtcPayNetwork network, object preparePaymentObject)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (preparePaymentObject is null)
|
||||||
|
{
|
||||||
|
return new MoneroLikeOnChainPaymentMethodDetails()
|
||||||
|
{
|
||||||
|
Activated = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!_moneroRpcProvider.IsAvailable(network.CryptoCode))
|
if (!_moneroRpcProvider.IsAvailable(network.CryptoCode))
|
||||||
throw new PaymentMethodUnavailableException($"Node or wallet not available");
|
throw new PaymentMethodUnavailableException($"Node or wallet not available");
|
||||||
@@ -49,7 +57,8 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
|||||||
NextNetworkFee = MoneroMoney.Convert(feeRatePerByte * 100),
|
NextNetworkFee = MoneroMoney.Convert(feeRatePerByte * 100),
|
||||||
AccountIndex = supportedPaymentMethod.AccountIndex,
|
AccountIndex = supportedPaymentMethod.AccountIndex,
|
||||||
AddressIndex = address.AddressIndex,
|
AddressIndex = address.AddressIndex,
|
||||||
DepositAddress = address.Address
|
DepositAddress = address.Address,
|
||||||
|
Activated = true
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -77,15 +86,22 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
|||||||
StoreBlob storeBlob, IPaymentMethod paymentMethod)
|
StoreBlob storeBlob, IPaymentMethod paymentMethod)
|
||||||
{
|
{
|
||||||
var paymentMethodId = paymentMethod.GetId();
|
var paymentMethodId = paymentMethod.GetId();
|
||||||
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
|
||||||
var network = _networkProvider.GetNetwork<MoneroLikeSpecificBtcPayNetwork>(model.CryptoCode);
|
var network = _networkProvider.GetNetwork<MoneroLikeSpecificBtcPayNetwork>(model.CryptoCode);
|
||||||
model.PaymentMethodName = GetPaymentMethodName(network);
|
model.PaymentMethodName = GetPaymentMethodName(network);
|
||||||
model.CryptoImage = GetCryptoImage(network);
|
model.CryptoImage = GetCryptoImage(network);
|
||||||
model.InvoiceBitcoinUrl = MoneroPaymentType.Instance.GetPaymentLink(network, new MoneroLikeOnChainPaymentMethodDetails()
|
if (model.Activated)
|
||||||
{
|
{
|
||||||
DepositAddress = cryptoInfo.Address
|
var cryptoInfo = invoiceResponse.CryptoInfo.First(o => o.GetpaymentMethodId() == paymentMethodId);
|
||||||
}, cryptoInfo.Due, null);
|
model.InvoiceBitcoinUrl = MoneroPaymentType.Instance.GetPaymentLink(network,
|
||||||
model.InvoiceBitcoinUrlQR = model.InvoiceBitcoinUrl;
|
new MoneroLikeOnChainPaymentMethodDetails() {DepositAddress = cryptoInfo.Address}, cryptoInfo.Due,
|
||||||
|
null);
|
||||||
|
model.InvoiceBitcoinUrlQR = model.InvoiceBitcoinUrl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
model.InvoiceBitcoinUrl = "";
|
||||||
|
model.InvoiceBitcoinUrlQR = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public override string GetCryptoImage(PaymentMethodId paymentMethodId)
|
public override string GetCryptoImage(PaymentMethodId paymentMethodId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
|||||||
|
|
||||||
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails, Money cryptoInfoDue, string serverUri)
|
public override string GetPaymentLink(BTCPayNetworkBase network, IPaymentMethodDetails paymentMethodDetails, Money cryptoInfoDue, string serverUri)
|
||||||
{
|
{
|
||||||
return
|
return paymentMethodDetails.Activated
|
||||||
$"{(network as MoneroLikeSpecificBtcPayNetwork).UriScheme}:{paymentMethodDetails.GetPaymentDestination()}?tx_amount={cryptoInfoDue.ToDecimal(MoneyUnit.BTC)}";
|
? $"{(network as MoneroLikeSpecificBtcPayNetwork).UriScheme}:{paymentMethodDetails.GetPaymentDestination()}?tx_amount={cryptoInfoDue.ToDecimal(MoneyUnit.BTC)}"
|
||||||
|
: string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string InvoiceViewPaymentPartialName { get; } = "Monero/ViewMoneroLikePaymentData";
|
public override string InvoiceViewPaymentPartialName { get; } = "Monero/ViewMoneroLikePaymentData";
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
var paymentMethod = invoice.GetPaymentMethod(payment.Network, MoneroPaymentType.Instance);
|
var paymentMethod = invoice.GetPaymentMethod(payment.Network, MoneroPaymentType.Instance);
|
||||||
if (paymentMethod != null &&
|
if (paymentMethod != null &&
|
||||||
paymentMethod.GetPaymentMethodDetails() is MoneroLikeOnChainPaymentMethodDetails monero &&
|
paymentMethod.GetPaymentMethodDetails() is MoneroLikeOnChainPaymentMethodDetails monero &&
|
||||||
|
monero.Activated &&
|
||||||
monero.GetPaymentDestination() == paymentData.GetDestination() &&
|
monero.GetPaymentDestination() == paymentData.GetDestination() &&
|
||||||
paymentMethod.Calculate().Due > Money.Zero)
|
paymentMethod.Calculate().Due > Money.Zero)
|
||||||
{
|
{
|
||||||
@@ -363,7 +364,8 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() { InvoiceId = invoiceIds });
|
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() { InvoiceId = invoiceIds });
|
||||||
invoices = invoices.Where(entity => entity.GetPaymentMethod(new PaymentMethodId(cryptoCode, MoneroPaymentType.Instance)) != null).ToArray();
|
invoices = invoices.Where(entity => entity.GetPaymentMethod(new PaymentMethodId(cryptoCode, MoneroPaymentType.Instance))
|
||||||
|
?.GetPaymentMethodDetails().Activated is true).ToArray();
|
||||||
_logger.LogInformation($"Updating pending payments for {cryptoCode} in {string.Join(',', invoiceIds)}");
|
_logger.LogInformation($"Updating pending payments for {cryptoCode} in {string.Join(',', invoiceIds)}");
|
||||||
await UpdatePaymentStates(cryptoCode, invoices);
|
await UpdatePaymentStates(cryptoCode, invoices);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
foreach (var strat in strategies.Properties())
|
foreach (var strat in strategies.Properties())
|
||||||
{
|
{
|
||||||
var paymentMethodId = PaymentMethodId.Parse(strat.Name);
|
var paymentMethodId = PaymentMethodId.Parse(strat.Name);
|
||||||
var network = Networks.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode);
|
var network = Networks.GetNetwork<BTCPayNetworkBase>(paymentMethodId.CryptoCode);
|
||||||
if (network != null)
|
if (network != null)
|
||||||
{
|
{
|
||||||
if (network == Networks.BTC && paymentMethodId.PaymentType == PaymentTypes.BTCLike)
|
if (network == Networks.BTC && paymentMethodId.PaymentType == PaymentTypes.BTCLike)
|
||||||
@@ -374,7 +374,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
|
|
||||||
if (paymentId.PaymentType == PaymentTypes.LightningLike)
|
if (details?.Activated is true && paymentId.PaymentType == PaymentTypes.LightningLike)
|
||||||
{
|
{
|
||||||
cryptoInfo.PaymentUrls = new InvoicePaymentUrls()
|
cryptoInfo.PaymentUrls = new InvoicePaymentUrls()
|
||||||
{
|
{
|
||||||
@@ -382,7 +382,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
ServerUrl)
|
ServerUrl)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (paymentId.PaymentType == PaymentTypes.BTCLike)
|
else if (details?.Activated is true && paymentId.PaymentType == PaymentTypes.BTCLike)
|
||||||
{
|
{
|
||||||
var minerInfo = new MinerFeeInfo();
|
var minerInfo = new MinerFeeInfo();
|
||||||
minerInfo.TotalFee = accounting.NetworkFee.Satoshi;
|
minerInfo.TotalFee = accounting.NetworkFee.Satoshi;
|
||||||
@@ -936,10 +936,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
|
|
||||||
private decimal GetTxFee()
|
private decimal GetTxFee()
|
||||||
{
|
{
|
||||||
var method = GetPaymentMethodDetails();
|
return GetPaymentMethodDetails()?.GetNextNetworkFee()?? 0m;
|
||||||
if (method == null)
|
|
||||||
return 0.0m;
|
|
||||||
return method.GetNextNetworkFee();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
52
BTCPayServer/Services/Invoices/InvoiceExtensions.cs
Normal file
52
BTCPayServer/Services/Invoices/InvoiceExtensions.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Data;
|
||||||
|
using BTCPayServer.Events;
|
||||||
|
using BTCPayServer.Logging;
|
||||||
|
using BTCPayServer.Payments;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Services.Invoices
|
||||||
|
{
|
||||||
|
public static class InvoiceExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
public static async Task ActivateInvoicePaymentMethod(this InvoiceRepository invoiceRepository,
|
||||||
|
EventAggregator eventAggregator, BTCPayNetworkProvider btcPayNetworkProvider, PaymentMethodHandlerDictionary paymentMethodHandlerDictionary,
|
||||||
|
StoreData store,InvoiceEntity invoice, PaymentMethodId paymentMethodId)
|
||||||
|
{
|
||||||
|
var eligibleMethodToActivate = invoice.GetPaymentMethod(paymentMethodId);
|
||||||
|
if (!eligibleMethodToActivate.GetPaymentMethodDetails().Activated)
|
||||||
|
{
|
||||||
|
var payHandler = paymentMethodHandlerDictionary[paymentMethodId];
|
||||||
|
var supportPayMethod = invoice.GetSupportedPaymentMethod()
|
||||||
|
.Single(method => method.PaymentId == paymentMethodId);
|
||||||
|
var paymentMethod = invoice.GetPaymentMethod(paymentMethodId);
|
||||||
|
var network = btcPayNetworkProvider.GetNetwork(paymentMethodId.CryptoCode);
|
||||||
|
var prepare = payHandler.PreparePayment(supportPayMethod, store, network);
|
||||||
|
InvoiceLogs logs = new InvoiceLogs();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logs.Write($"{paymentMethodId}: Activating", InvoiceEventData.EventSeverity.Info);
|
||||||
|
var newDetails = await
|
||||||
|
payHandler.CreatePaymentMethodDetails(logs, supportPayMethod, paymentMethod, store, network,
|
||||||
|
prepare);
|
||||||
|
eligibleMethodToActivate.SetPaymentMethodDetails(newDetails);
|
||||||
|
await invoiceRepository.UpdateInvoicePaymentMethod(invoice.Id, eligibleMethodToActivate);
|
||||||
|
}
|
||||||
|
catch (PaymentMethodUnavailableException ex)
|
||||||
|
{
|
||||||
|
logs.Write($"{paymentMethodId}: Payment method unavailable ({ex.Message})", InvoiceEventData.EventSeverity.Error);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logs.Write($"{paymentMethodId}: Unexpected exception ({ex})", InvoiceEventData.EventSeverity.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
await invoiceRepository.AddInvoiceLogs(invoice.Id, logs);
|
||||||
|
eventAggregator.Publish(new InvoiceNeedUpdateEvent(invoice.Id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NLog;
|
||||||
using Encoders = NBitcoin.DataEncoders.Encoders;
|
using Encoders = NBitcoin.DataEncoders.Encoders;
|
||||||
using InvoiceData = BTCPayServer.Data.InvoiceData;
|
using InvoiceData = BTCPayServer.Data.InvoiceData;
|
||||||
|
|
||||||
@@ -180,8 +181,12 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
{
|
{
|
||||||
if (paymentMethod.Network == null)
|
if (paymentMethod.Network == null)
|
||||||
throw new InvalidOperationException("CryptoCode unsupported");
|
throw new InvalidOperationException("CryptoCode unsupported");
|
||||||
var paymentDestination = paymentMethod.GetPaymentMethodDetails().GetPaymentDestination();
|
var details = paymentMethod.GetPaymentMethodDetails();
|
||||||
|
if (!details.Activated)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var paymentDestination = details.GetPaymentDestination();
|
||||||
string address = GetDestination(paymentMethod);
|
string address = GetDestination(paymentMethod);
|
||||||
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
|
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
|
||||||
{
|
{
|
||||||
@@ -244,7 +249,13 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
if (paymentMethod.GetId().PaymentType == Payments.PaymentTypes.BTCLike)
|
if (paymentMethod.GetId().PaymentType == Payments.PaymentTypes.BTCLike)
|
||||||
{
|
{
|
||||||
var network = (BTCPayNetwork)paymentMethod.Network;
|
var network = (BTCPayNetwork)paymentMethod.Network;
|
||||||
return ((Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod)paymentMethod.GetPaymentMethodDetails()).GetDepositAddress(network.NBitcoinNetwork).ScriptPubKey.Hash.ToString();
|
var details =
|
||||||
|
(Payments.Bitcoin.BitcoinLikeOnChainPaymentMethod)paymentMethod.GetPaymentMethodDetails();
|
||||||
|
if (!details.Activated)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return details.GetDepositAddress(network.NBitcoinNetwork).ScriptPubKey.Hash.ToString();
|
||||||
}
|
}
|
||||||
///////////////
|
///////////////
|
||||||
return paymentMethod.GetPaymentMethodDetails().GetPaymentDestination();
|
return paymentMethod.GetPaymentMethodDetails().GetPaymentDestination();
|
||||||
@@ -294,6 +305,39 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task UpdateInvoicePaymentMethod(string invoiceId, PaymentMethod paymentMethod)
|
||||||
|
{
|
||||||
|
using (var context = _ContextFactory.CreateContext())
|
||||||
|
{
|
||||||
|
var invoice = await context.Invoices.FindAsync(invoiceId);
|
||||||
|
if (invoice == null)
|
||||||
|
return;
|
||||||
|
var network = paymentMethod.Network;
|
||||||
|
var invoiceEntity = invoice.GetBlob(_Networks);
|
||||||
|
var newDetails = paymentMethod.GetPaymentMethodDetails();
|
||||||
|
var existing = invoiceEntity.GetPaymentMethod(paymentMethod.GetId());
|
||||||
|
if (existing.GetPaymentMethodDetails().GetPaymentDestination() != newDetails.GetPaymentDestination() && newDetails.Activated)
|
||||||
|
{
|
||||||
|
await context.AddressInvoices.AddAsync(new AddressInvoiceData()
|
||||||
|
{
|
||||||
|
InvoiceDataId = invoiceId,
|
||||||
|
CreatedTime = DateTimeOffset.UtcNow
|
||||||
|
}
|
||||||
|
.Set(GetDestination(paymentMethod), paymentMethod.GetId()));
|
||||||
|
await context.HistoricalAddressInvoices.AddAsync(new HistoricalAddressInvoiceData()
|
||||||
|
{
|
||||||
|
InvoiceDataId = invoiceId,
|
||||||
|
Assigned = DateTimeOffset.UtcNow
|
||||||
|
}.SetAddress(paymentMethod.GetPaymentMethodDetails().GetPaymentDestination(), network.CryptoCode));
|
||||||
|
}
|
||||||
|
invoiceEntity.SetPaymentMethod(paymentMethod);
|
||||||
|
invoice.Blob = ToBytes(invoiceEntity, network);
|
||||||
|
AddToTextSearch(context, invoice, paymentMethod.GetPaymentMethodDetails().GetPaymentDestination());
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task AddPendingInvoiceIfNotPresent(string invoiceId)
|
public async Task AddPendingInvoiceIfNotPresent(string invoiceId)
|
||||||
{
|
{
|
||||||
using (var context = _ContextFactory.CreateContext())
|
using (var context = _ContextFactory.CreateContext())
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</line-items>
|
</line-items>
|
||||||
<component v-if="srvModel.uiSettings && srvModel.uiSettings.checkoutHeaderVueComponentName"
|
<component v-if="srvModel.uiSettings && srvModel.uiSettings.checkoutHeaderVueComponentName && srvModel.activated"
|
||||||
v-bind:srv-model="srvModel"
|
v-bind:srv-model="srvModel"
|
||||||
v-bind:is="srvModel.uiSettings.checkoutHeaderVueComponentName">
|
v-bind:is="srvModel.uiSettings.checkoutHeaderVueComponentName">
|
||||||
</component>
|
</component>
|
||||||
@@ -184,7 +184,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showPaymentUI">
|
<div v-if="showPaymentUI">
|
||||||
<component v-if="srvModel.uiSettings && srvModel.uiSettings.checkoutBodyVueComponentName"
|
<component v-if="srvModel.uiSettings && srvModel.uiSettings.checkoutBodyVueComponentName && srvModel.activated"
|
||||||
v-bind:srv-model="srvModel"
|
v-bind:srv-model="srvModel"
|
||||||
v-bind:is="srvModel.uiSettings.checkoutBodyVueComponentName">
|
v-bind:is="srvModel.uiSettings.checkoutBodyVueComponentName">
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -80,6 +80,12 @@
|
|||||||
<label asp-for="OnChainWithLnInvoiceFallback" class="form-check-label"></label>
|
<label asp-for="OnChainWithLnInvoiceFallback" class="form-check-label"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input asp-for="LazyPaymentMethods" type="checkbox" class="form-check-input" />
|
||||||
|
<label asp-for="LazyPaymentMethods" class="form-check-label"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input asp-for="RedirectAutomatically" type="checkbox" class="form-check-input" />
|
<input asp-for="RedirectAutomatically" type="checkbox" class="form-check-input" />
|
||||||
|
|||||||
@@ -542,6 +542,71 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods/{paymentMethod}/activate": {
|
||||||
|
"post": {
|
||||||
|
"tags": [
|
||||||
|
"Invoices"
|
||||||
|
],
|
||||||
|
"summary": "Activate Payment Method",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "storeId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"description": "The store to query",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "invoiceId",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"description": "The invoice to update",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "paymentMethod",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"description": "The payment method to activate",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Activate an invoice payment method (if lazy payments mode is enabled)",
|
||||||
|
"operationId": "Invoices_ActivatePaymentMethod",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "A list of errors that occurred when updating the invoice",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ValidationProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "If you are authenticated but forbidden to activate the invoice payment method"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"API Key": [
|
||||||
|
"btcpay.store.canviewinvoices"
|
||||||
|
],
|
||||||
|
"Basic": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
@@ -729,7 +794,7 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"description": "A specific set of payment methods to use for this invoice (ie. BTC, BTC-LightningNetwork). By default, select all payment methods activated in the store."
|
"description": "A specific set of payment methods to use for this invoice (ie. BTC, BTC-LightningNetwork). By default, select all payment methods enabled in the store."
|
||||||
},
|
},
|
||||||
"expirationMinutes": {
|
"expirationMinutes": {
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
@@ -837,6 +902,10 @@
|
|||||||
"$ref": "#/components/schemas/Payment"
|
"$ref": "#/components/schemas/Payment"
|
||||||
},
|
},
|
||||||
"description": "Payments made with this payment method."
|
"description": "Payments made with this payment method."
|
||||||
|
},
|
||||||
|
"activated": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "If the payment method is activated (when lazy payments option is enabled"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -381,6 +381,11 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "If true, payjoin will be proposed in the checkout page if possible. ([More information](https://docs.btcpayserver.org/Payjoin/))"
|
"description": "If true, payjoin will be proposed in the checkout page if possible. ([More information](https://docs.btcpayserver.org/Payjoin/))"
|
||||||
},
|
},
|
||||||
|
"lazyPaymentMethods": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "If true, payment methods are enabled individually upon user interaction in the invoice"
|
||||||
|
},
|
||||||
"defaultPaymentMethod": {
|
"defaultPaymentMethod": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "BTC",
|
"example": "BTC",
|
||||||
|
|||||||
Reference in New Issue
Block a user