Make LNURL enabled when only method (#3930)

* Make LNURL enabled when only method

This fixes the scenario where LNURL for standard invoices are disabled, but the POS Print view only shows LNURL, so the QR code would always error out. The fix is to bypass the setting when lnurl is the only enabled payment method on the invoice

* Make sure not to affect other flows

* fix
This commit is contained in:
Andrew Camilleri
2022-07-06 15:09:05 +02:00
committed by GitHub
parent 3576ebd14f
commit 612a0397a7
10 changed files with 39 additions and 24 deletions

View File

@@ -281,18 +281,20 @@ namespace BTCPayServer.Controllers
// This loop ends with .ToList so we are querying all payment methods at once // This loop ends with .ToList so we are querying all payment methods at once
// instead of sequentially to improve response time // instead of sequentially to improve response time
foreach (var o in store.GetSupportedPaymentMethods(_NetworkProvider) var x1 = store.GetSupportedPaymentMethods(_NetworkProvider)
.Where(s => !excludeFilter.Match(s.PaymentId) && .Where(s => !excludeFilter.Match(s.PaymentId) &&
_paymentMethodHandlerDictionary.Support(s.PaymentId)) _paymentMethodHandlerDictionary.Support(s.PaymentId))
.Select(c => .Select(c =>
(Handler: _paymentMethodHandlerDictionary[c.PaymentId], (Handler: _paymentMethodHandlerDictionary[c.PaymentId],
SupportedPaymentMethod: c, SupportedPaymentMethod: c,
Network: _NetworkProvider.GetNetwork<BTCPayNetworkBase>(c.PaymentId.CryptoCode))) Network: _NetworkProvider.GetNetwork<BTCPayNetworkBase>(c.PaymentId.CryptoCode)))
.Where(c => c.Network != null) .Where(c => c.Network != null).ToList();
var pmis = x1.Select(tuple => tuple.SupportedPaymentMethod.PaymentId).ToHashSet();
foreach (var o in x1
.Select(o => .Select(o =>
(SupportedPaymentMethod: o.SupportedPaymentMethod, (SupportedPaymentMethod: o.SupportedPaymentMethod,
PaymentMethod: CreatePaymentMethodAsync(fetchingByCurrencyPair, o.Handler, PaymentMethod: CreatePaymentMethodAsync(fetchingByCurrencyPair, o.Handler,
o.SupportedPaymentMethod, o.Network, entity, store, logs))) o.SupportedPaymentMethod, o.Network, entity, store, logs, pmis)))
.ToList()) .ToList())
{ {
var paymentMethod = await o.PaymentMethod; var paymentMethod = await o.PaymentMethod;
@@ -362,9 +364,12 @@ namespace BTCPayServer.Controllers
}).ToArray()); }).ToArray());
} }
private async Task<PaymentMethod?> CreatePaymentMethodAsync(Dictionary<CurrencyPair, Task<RateResult>> fetchingByCurrencyPair, private async Task<PaymentMethod?> CreatePaymentMethodAsync(
IPaymentMethodHandler handler, ISupportedPaymentMethod supportedPaymentMethod, BTCPayNetworkBase network, InvoiceEntity entity, Dictionary<CurrencyPair, Task<RateResult>> fetchingByCurrencyPair,
StoreData store, InvoiceLogs logs) IPaymentMethodHandler handler, ISupportedPaymentMethod supportedPaymentMethod, BTCPayNetworkBase network,
InvoiceEntity entity,
StoreData store, InvoiceLogs logs,
HashSet<PaymentMethodId> invoicePaymentMethods)
{ {
try try
{ {
@@ -396,7 +401,7 @@ namespace BTCPayServer.Controllers
using (logs.Measure($"{logPrefix} Payment method details creation")) using (logs.Measure($"{logPrefix} Payment method details creation"))
{ {
var paymentDetails = await handler.CreatePaymentMethodDetails(logs, supportedPaymentMethod, paymentMethod, store, network, preparePayment); var paymentDetails = await handler.CreatePaymentMethodDetails(logs, supportedPaymentMethod, paymentMethod, store, network, preparePayment, invoicePaymentMethods);
paymentMethod.SetPaymentMethodDetails(paymentDetails); paymentMethod.SetPaymentMethodDetails(paymentDetails);
} }

View File

@@ -474,8 +474,7 @@ namespace BTCPayServer
var isTopup = i.IsUnsetTopUp(); var isTopup = i.IsUnsetTopUp();
var lnurlSupportedPaymentMethod = var lnurlSupportedPaymentMethod =
i.GetSupportedPaymentMethod<LNURLPaySupportedPaymentMethod>(pmi).FirstOrDefault(); i.GetSupportedPaymentMethod<LNURLPaySupportedPaymentMethod>(pmi).FirstOrDefault();
if (lnurlSupportedPaymentMethod is null || if (lnurlSupportedPaymentMethod is null)
(!isTopup && !lnurlSupportedPaymentMethod.EnableForStandardInvoices))
{ {
return NotFound(); return NotFound();
} }

View File

@@ -153,7 +153,7 @@ namespace BTCPayServer.Payments.Bitcoin
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails( public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(
InvoiceLogs logs, InvoiceLogs logs,
DerivationSchemeSettings supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store, DerivationSchemeSettings supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store,
BTCPayNetwork network, object preparePaymentObject) BTCPayNetwork network, object preparePaymentObject, IEnumerable<PaymentMethodId> invoicePaymentMethods)
{ {
if (preparePaymentObject is null) if (preparePaymentObject is null)
{ {

View File

@@ -20,14 +20,18 @@ namespace BTCPayServer.Payments
/// <summary> /// <summary>
/// Create needed to track payments of this invoice /// Create needed to track payments of this invoice
/// </summary> /// </summary>
/// <param name="logs"></param>
/// <param name="supportedPaymentMethod"></param> /// <param name="supportedPaymentMethod"></param>
/// <param name="paymentMethod"></param> /// <param name="paymentMethod"></param>
/// <param name="store"></param> /// <param name="store"></param>
/// <param name="network"></param> /// <param name="network"></param>
/// <param name="preparePaymentObject"></param> /// <param name="preparePaymentObject"></param>
/// <param name="invoicePaymentMethods"></param>
/// <returns></returns> /// <returns></returns>
Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, ISupportedPaymentMethod supportedPaymentMethod, Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs,
PaymentMethod paymentMethod, StoreData store, BTCPayNetworkBase network, object preparePaymentObject); ISupportedPaymentMethod supportedPaymentMethod,
PaymentMethod paymentMethod, StoreData store, BTCPayNetworkBase network, object preparePaymentObject,
IEnumerable<PaymentMethodId> invoicePaymentMethods);
/// <summary> /// <summary>
/// This method called before the rate have been fetched /// This method called before the rate have been fetched
@@ -52,7 +56,7 @@ namespace BTCPayServer.Payments
where TBTCPayNetwork : BTCPayNetworkBase where TBTCPayNetwork : BTCPayNetworkBase
{ {
Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, TSupportedPaymentMethod supportedPaymentMethod, Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, TSupportedPaymentMethod supportedPaymentMethod,
PaymentMethod paymentMethod, StoreData store, TBTCPayNetwork network, object preparePaymentObject); PaymentMethod paymentMethod, StoreData store, TBTCPayNetwork network, object preparePaymentObject, IEnumerable<PaymentMethodId> invoicePaymentMethods);
} }
public abstract class PaymentMethodHandlerBase<TSupportedPaymentMethod, TBTCPayNetwork> : IPaymentMethodHandler< public abstract class PaymentMethodHandlerBase<TSupportedPaymentMethod, TBTCPayNetwork> : IPaymentMethodHandler<
@@ -65,7 +69,7 @@ namespace BTCPayServer.Payments
public abstract Task<IPaymentMethodDetails> CreatePaymentMethodDetails( public abstract Task<IPaymentMethodDetails> CreatePaymentMethodDetails(
InvoiceLogs logs, InvoiceLogs logs,
TSupportedPaymentMethod supportedPaymentMethod, TSupportedPaymentMethod supportedPaymentMethod,
PaymentMethod paymentMethod, StoreData store, TBTCPayNetwork network, object preparePaymentObject); PaymentMethod paymentMethod, StoreData store, TBTCPayNetwork network, object preparePaymentObject, IEnumerable<PaymentMethodId> invoicePaymentMethods);
public abstract void PreparePaymentModel(PaymentModel model, InvoiceResponse invoiceResponse, public abstract void PreparePaymentModel(PaymentModel model, InvoiceResponse invoiceResponse,
StoreBlob storeBlob, IPaymentMethod paymentMethod); StoreBlob storeBlob, IPaymentMethod paymentMethod);
@@ -95,12 +99,14 @@ namespace BTCPayServer.Payments
return null; return null;
} }
public Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, ISupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, public Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs,
StoreData store, BTCPayNetworkBase network, object preparePaymentObject) ISupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod,
StoreData store, BTCPayNetworkBase network, object preparePaymentObject,
IEnumerable<PaymentMethodId> invoicePaymentMethods)
{ {
if (supportedPaymentMethod is TSupportedPaymentMethod method && network is TBTCPayNetwork correctNetwork) if (supportedPaymentMethod is TSupportedPaymentMethod method && network is TBTCPayNetwork correctNetwork)
{ {
return CreatePaymentMethodDetails(logs, method, paymentMethod, store, correctNetwork, preparePaymentObject); return CreatePaymentMethodDetails(logs, method, paymentMethod, store, correctNetwork, preparePaymentObject, invoicePaymentMethods);
} }
throw new NotSupportedException("Invalid supportedPaymentMethod"); throw new NotSupportedException("Invalid supportedPaymentMethod");

View File

@@ -46,10 +46,12 @@ namespace BTCPayServer.Payments.Lightning
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails( public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(
InvoiceLogs logs, InvoiceLogs logs,
LNURLPaySupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, Data.StoreData store, LNURLPaySupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, Data.StoreData store,
BTCPayNetwork network, object preparePaymentObject) BTCPayNetwork network, object preparePaymentObject, IEnumerable<PaymentMethodId> invoicePaymentMethods)
{ {
var lnPmi = new PaymentMethodId(supportedPaymentMethod.CryptoCode, PaymentTypes.LightningLike);
if (!supportedPaymentMethod.EnableForStandardInvoices && if (!supportedPaymentMethod.EnableForStandardInvoices &&
paymentMethod.ParentEntity.Type == InvoiceType.Standard) paymentMethod.ParentEntity.Type == InvoiceType.Standard &&
invoicePaymentMethods.Contains(lnPmi))
{ {
throw new PaymentMethodUnavailableException("LNURL is not enabled for standard invoices"); throw new PaymentMethodUnavailableException("LNURL is not enabled for standard invoices");
} }

View File

@@ -53,7 +53,7 @@ namespace BTCPayServer.Payments.Lightning
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails( public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(
InvoiceLogs logs, InvoiceLogs logs,
LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, Data.StoreData store, LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, Data.StoreData store,
BTCPayNetwork network, object preparePaymentObject) BTCPayNetwork network, object preparePaymentObject, IEnumerable<PaymentMethodId> invoicePaymentMethods)
{ {
if (supportedPaymentMethod.DisableBOLT11PaymentOption) if (supportedPaymentMethod.DisableBOLT11PaymentOption)
{ {

View File

@@ -298,10 +298,12 @@ namespace BTCPayServer.Payments.Lightning
var prepObj = var prepObj =
_lightningLikePaymentHandler.PreparePayment(supportedMethod, store, paymentMethod.Network); _lightningLikePaymentHandler.PreparePayment(supportedMethod, store, paymentMethod.Network);
var pmis = invoice.GetPaymentMethods().Select(method => method.GetId()).ToHashSet();
var newPaymentMethodDetails = var newPaymentMethodDetails =
(LightningLikePaymentMethodDetails)(await _lightningLikePaymentHandler (LightningLikePaymentMethodDetails)(await _lightningLikePaymentHandler
.CreatePaymentMethodDetails(logs, supportedMethod, paymentMethod, store, .CreatePaymentMethodDetails(logs, supportedMethod, paymentMethod, store,
paymentMethod.Network, prepObj)); paymentMethod.Network, prepObj, pmis));
var instanceListenerKey = (paymentMethod.Network.CryptoCode, var instanceListenerKey = (paymentMethod.Network.CryptoCode,
GetLightningUrl(supportedMethod).ToString()); GetLightningUrl(supportedMethod).ToString());

View File

@@ -32,7 +32,7 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
public override PaymentType PaymentType => MoneroPaymentType.Instance; public override PaymentType PaymentType => MoneroPaymentType.Instance;
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, IEnumerable<PaymentMethodId> invoicePaymentMethods)
{ {
if (preparePaymentObject is null) if (preparePaymentObject is null)

View File

@@ -32,7 +32,7 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Payments
public override PaymentType PaymentType => ZcashPaymentType.Instance; public override PaymentType PaymentType => ZcashPaymentType.Instance;
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, ZcashSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(InvoiceLogs logs, ZcashSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod,
StoreData store, ZcashLikeSpecificBtcPayNetwork network, object preparePaymentObject) StoreData store, ZcashLikeSpecificBtcPayNetwork network, object preparePaymentObject, IEnumerable<PaymentMethodId> invoicePaymentMethods)
{ {
if (preparePaymentObject is null) if (preparePaymentObject is null)

View File

@@ -30,10 +30,11 @@ namespace BTCPayServer.Services.Invoices
InvoiceLogs logs = new InvoiceLogs(); InvoiceLogs logs = new InvoiceLogs();
try try
{ {
var pmis = invoice.GetPaymentMethods().Select(method => method.GetId()).ToHashSet();
logs.Write($"{paymentMethodId}: Activating", InvoiceEventData.EventSeverity.Info); logs.Write($"{paymentMethodId}: Activating", InvoiceEventData.EventSeverity.Info);
var newDetails = await var newDetails = await
payHandler.CreatePaymentMethodDetails(logs, supportPayMethod, paymentMethod, store, network, payHandler.CreatePaymentMethodDetails(logs, supportPayMethod, paymentMethod, store, network,
prepare); prepare, pmis);
eligibleMethodToActivate.SetPaymentMethodDetails(newDetails); eligibleMethodToActivate.SetPaymentMethodDetails(newDetails);
await invoiceRepository.UpdateInvoicePaymentMethod(invoice.Id, eligibleMethodToActivate); await invoiceRepository.UpdateInvoicePaymentMethod(invoice.Id, eligibleMethodToActivate);
eventAggregator.Publish(new InvoicePaymentMethodActivated(paymentMethodId, invoice)); eventAggregator.Publish(new InvoicePaymentMethodActivated(paymentMethodId, invoice));