Checkout fixes (#4375)

* Round buttons on results view

* Checkout v2: Fix for BIP21 case with LN as default payment method

Fixes #4352.

* Update changelog

* Add test for fix
This commit is contained in:
d11n
2022-11-29 03:19:23 +01:00
committed by GitHub
parent e55a16d917
commit 9ee9653c7d
4 changed files with 36 additions and 11 deletions

View File

@@ -151,6 +151,15 @@ namespace BTCPayServer.Tests
Assert.StartsWith("bitcoin:", payUrl); Assert.StartsWith("bitcoin:", payUrl);
Assert.Contains("&LIGHTNING=", payUrl); Assert.Contains("&LIGHTNING=", payUrl);
// BIP21 with LN as default payment method
s.GoToHome();
invoiceId = s.CreateInvoice(defaultPaymentMethod: "BTC_LightningLike");
s.GoToInvoiceCheckout(invoiceId);
Assert.Empty(s.Driver.FindElements(By.CssSelector(".payment-method")));
payUrl = s.Driver.FindElement(By.CssSelector(".btn-primary")).GetAttribute("href");
Assert.StartsWith("bitcoin:", payUrl);
Assert.Contains("&LIGHTNING=", payUrl);
// BIP21 with topup invoice (which is only available with Bitcoin onchain) // BIP21 with topup invoice (which is only available with Bitcoin onchain)
s.GoToHome(); s.GoToHome();
invoiceId = s.CreateInvoice(amount: null); invoiceId = s.CreateInvoice(amount: null);

View File

@@ -643,9 +643,23 @@ namespace BTCPayServer.Controllers
return null; return null;
bool isDefaultPaymentId = false; bool isDefaultPaymentId = false;
var storeBlob = store.GetStoreBlob();
var btcId = PaymentMethodId.Parse("BTC");
var lnId = PaymentMethodId.Parse("BTC_LightningLike");
if (paymentMethodId is null) if (paymentMethodId is null)
{ {
var enabledPaymentIds = store.GetEnabledPaymentIds(_NetworkProvider); var enabledPaymentIds = store.GetEnabledPaymentIds(_NetworkProvider)
// Exclude LNURL for Checkout v2
.Where(pmId => storeBlob.CheckoutType == CheckoutType.V1 || pmId.PaymentType is not LNURLPayPaymentType)
.ToArray();
// Exclude Lightning if OnChainWithLnInvoiceFallback is active and we have both payment methods
if (storeBlob.CheckoutType == CheckoutType.V2 && storeBlob.OnChainWithLnInvoiceFallback &&
enabledPaymentIds.Contains(btcId) && enabledPaymentIds.Contains(lnId))
{
enabledPaymentIds = enabledPaymentIds.Where(pmId => pmId != lnId).ToArray();
}
PaymentMethodId? invoicePaymentId = invoice.GetDefaultPaymentMethod(); PaymentMethodId? invoicePaymentId = invoice.GetDefaultPaymentMethod();
PaymentMethodId? storePaymentId = store.GetDefaultPaymentId(); PaymentMethodId? storePaymentId = store.GetDefaultPaymentId();
if (invoicePaymentId is not null) if (invoicePaymentId is not null)
@@ -676,6 +690,7 @@ namespace BTCPayServer.Controllers
} }
if (paymentMethodId is null) if (paymentMethodId is null)
return null; return null;
BTCPayNetworkBase network = _NetworkProvider.GetNetwork<BTCPayNetworkBase>(paymentMethodId.CryptoCode); BTCPayNetworkBase network = _NetworkProvider.GetNetwork<BTCPayNetworkBase>(paymentMethodId.CryptoCode);
if (network is null || !invoice.Support(paymentMethodId)) if (network is null || !invoice.Support(paymentMethodId))
{ {
@@ -702,12 +717,10 @@ namespace BTCPayServer.Controllers
return await GetInvoiceModel(invoiceId, paymentMethodId, lang); return await GetInvoiceModel(invoiceId, paymentMethodId, lang);
} }
} }
var dto = invoice.EntityToDTO(); var dto = invoice.EntityToDTO();
var storeBlob = store.GetStoreBlob();
var accounting = paymentMethod.Calculate(); var accounting = paymentMethod.Calculate();
var paymentMethodHandler = _paymentMethodHandlerDictionary[paymentMethodId]; var paymentMethodHandler = _paymentMethodHandlerDictionary[paymentMethodId];
var divisibility = _CurrencyNameTable.GetNumberFormatInfo(paymentMethod.GetId().CryptoCode, false)?.CurrencyDecimalDigits; var divisibility = _CurrencyNameTable.GetNumberFormatInfo(paymentMethod.GetId().CryptoCode, false)?.CurrencyDecimalDigits;
switch (lang?.ToLowerInvariant()) switch (lang?.ToLowerInvariant())
@@ -810,16 +823,18 @@ namespace BTCPayServer.Controllers
.OrderByDescending(a => a.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode).ThenBy(a => a.PaymentMethodName).ThenBy(a => a.IsLightning ? 1 : 0) .OrderByDescending(a => a.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode).ThenBy(a => a.PaymentMethodName).ThenBy(a => a.IsLightning ? 1 : 0)
.ToList() .ToList()
}; };
// Exclude Lightning if OnChainWithLnInvoiceFallback is active and we have both payment methods // Exclude Lightning if OnChainWithLnInvoiceFallback is active and we have both payment methods
if (storeBlob.CheckoutType == CheckoutType.V2 && storeBlob.OnChainWithLnInvoiceFallback) if (storeBlob.CheckoutType == CheckoutType.V2 && storeBlob.OnChainWithLnInvoiceFallback)
{ {
var onchainPM = model.AvailableCryptos.Find(c => c.PaymentMethodId == "BTC"); var onchainPM = model.AvailableCryptos.Find(c => c.PaymentMethodId == btcId.ToString());
var lightningPM = model.AvailableCryptos.Find(c => c.PaymentMethodId == "BTC_LightningLike"); var lightningPM = model.AvailableCryptos.Find(c => c.PaymentMethodId == lnId.ToString());
if (onchainPM != null && lightningPM != null) if (onchainPM != null && lightningPM != null)
{ {
model.AvailableCryptos.Remove(lightningPM); model.AvailableCryptos.Remove(lightningPM);
} }
} }
paymentMethodHandler.PreparePaymentModel(model, dto, storeBlob, paymentMethod); paymentMethodHandler.PreparePaymentModel(model, dto, storeBlob, paymentMethod);
model.UISettings = paymentMethodHandler.GetCheckoutUISettings(); model.UISettings = paymentMethodHandler.GetCheckoutUISettings();
model.PaymentMethodId = paymentMethodId.ToString(); model.PaymentMethodId = paymentMethodId.ToString();

View File

@@ -134,9 +134,9 @@
<payment-details :srv-model="srvModel" :is-active="isActive" class="mb-5"></payment-details> <payment-details :srv-model="srvModel" :is-active="isActive" class="mb-5"></payment-details>
</div> </div>
<div class="buttons"> <div class="buttons">
<a v-if="srvModel.receiptLink" class="btn btn-primary" :href="srvModel.receiptLink" :target="isModal ? '_top' : null" v-t="'view_receipt'" id="ReceiptLink"></a> <a v-if="srvModel.receiptLink" class="btn btn-primary rounded-pill w-100" :href="srvModel.receiptLink" :target="isModal ? '_top' : null" v-t="'view_receipt'" id="ReceiptLink"></a>
<a v-if="storeLink" class="btn btn-secondary" :href="storeLink" :target="isModal ? '_top' : null" v-t="{ path: 'return_to_store', args: { storeName: srvModel.storeName }}" id="StoreLink"></a> <a v-if="storeLink" class="btn btn-secondary rounded-pill w-100" :href="storeLink" :target="isModal ? '_top' : null" v-t="{ path: 'return_to_store', args: { storeName: srvModel.storeName }}" id="StoreLink"></a>
<button v-else-if="isModal" class="btn btn-secondary" v-on:click="close" v-t="'Close'"></button> <button v-else-if="isModal" class="btn btn-secondary rounded-pill w-100" v-on:click="close" v-t="'Close'"></button>
</div> </div>
</div> </div>
<div id="expired" v-if="isUnpayable"> <div id="expired" v-if="isUnpayable">
@@ -165,8 +165,8 @@
<p class="text-center mt-3" v-html="replaceNewlines($t('invoice_expired_body', { storeName: srvModel.storeName, minutes: @Model.MaxTimeMinutes }))"></p> <p class="text-center mt-3" v-html="replaceNewlines($t('invoice_expired_body', { storeName: srvModel.storeName, minutes: @Model.MaxTimeMinutes }))"></p>
</div> </div>
<div class="buttons"> <div class="buttons">
<a v-if="storeLink" class="btn btn-primary" :href="storeLink" :target="isModal ? '_top' : null" v-t="{ path: 'return_to_store', args: { storeName: srvModel.storeName }}" id="StoreLink"></a> <a v-if="storeLink" class="btn btn-primary rounded-pill w-100" :href="storeLink" :target="isModal ? '_top' : null" v-t="{ path: 'return_to_store', args: { storeName: srvModel.storeName }}" id="StoreLink"></a>
<button v-else-if="isModal" class="btn btn-primary" v-on:click="close" v-t="'Close'"></button> <button v-else-if="isModal" class="btn btn-primary rounded-pill w-100" v-on:click="close" v-t="'Close'"></button>
</div> </div>
</div> </div>
</section> </section>

View File

@@ -13,6 +13,7 @@
* Some logos or images wouldn't show up properly if rootPath is used (#4367) @NicolasDorier * Some logos or images wouldn't show up properly if rootPath is used (#4367) @NicolasDorier
* Fix malformed manifest on PoS app (#4373, #4363) @dennisreimann * Fix malformed manifest on PoS app (#4373, #4363) @dennisreimann
* Call to LND would start failing on some conditions @NicolasDorier * Call to LND would start failing on some conditions @NicolasDorier
* Checkout v2: Fix for BIP21 case with default payment method other than onchain BTC (#4375) @dennisreimann
### Improvement ### Improvement