mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-02-22 06:34:36 +01:00
Merge pull request #6282 from NicolasDorier/refactorcheckout
Allow payment methods to modify all the payment model
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
|
||||
namespace BTCPayServer.Abstractions.Services
|
||||
{
|
||||
public class UIExtension : IUIExtension
|
||||
{
|
||||
[Obsolete("Use extension method BTCPayServer.Extensions.AddUIExtension(this IServiceCollection services, string location, string partialViewName) instead")]
|
||||
public UIExtension(string partial, string location)
|
||||
{
|
||||
Partial = partial;
|
||||
|
||||
@@ -320,10 +320,10 @@ namespace BTCPayServer.Tests
|
||||
|
||||
var controller = tester.PayTester.GetController<UIInvoiceController>(null);
|
||||
var checkout =
|
||||
(Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id)
|
||||
(Models.InvoicingModels.CheckoutModel)((JsonResult)controller.GetStatus(invoice.Id)
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Single(checkout.AvailableCryptos);
|
||||
Assert.Equal("LTC", checkout.CryptoCode);
|
||||
Assert.Single(checkout.AvailablePaymentMethods);
|
||||
Assert.Equal("LTC", checkout.PaymentMethodCurrency);
|
||||
|
||||
//////////////////////
|
||||
|
||||
@@ -337,7 +337,7 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
invoice = user.BitPay.GetInvoice(invoice.Id);
|
||||
Assert.Equal("paid", invoice.Status);
|
||||
checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id)
|
||||
checkout = (Models.InvoicingModels.CheckoutModel)((JsonResult)controller.GetStatus(invoice.Id)
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Equal("Processing", checkout.Status);
|
||||
});
|
||||
@@ -475,10 +475,10 @@ namespace BTCPayServer.Tests
|
||||
|
||||
var controller = tester.PayTester.GetController<UIInvoiceController>(null);
|
||||
var checkout =
|
||||
(Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, null)
|
||||
(Models.InvoicingModels.CheckoutModel)((JsonResult)controller.GetStatus(invoice.Id, null)
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Single(checkout.AvailableCryptos);
|
||||
Assert.Equal("BTC", checkout.CryptoCode);
|
||||
Assert.Single(checkout.AvailablePaymentMethods);
|
||||
Assert.Equal("BTC", checkout.PaymentMethodCurrency);
|
||||
|
||||
Assert.Single(invoice.PaymentCodes);
|
||||
Assert.Single(invoice.SupportedTransactionCurrencies);
|
||||
@@ -536,10 +536,10 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
|
||||
controller = tester.PayTester.GetController<UIInvoiceController>(null);
|
||||
checkout = (Models.InvoicingModels.PaymentModel)((JsonResult)controller.GetStatus(invoice.Id, "LTC")
|
||||
checkout = (Models.InvoicingModels.CheckoutModel)((JsonResult)controller.GetStatus(invoice.Id, "LTC")
|
||||
.GetAwaiter().GetResult()).Value;
|
||||
Assert.Equal(2, checkout.AvailableCryptos.Count);
|
||||
Assert.Equal("LTC", checkout.CryptoCode);
|
||||
Assert.Equal(2, checkout.AvailablePaymentMethods.Count);
|
||||
Assert.Equal("LTC", checkout.PaymentMethodCurrency);
|
||||
|
||||
Assert.Equal(2, invoice.PaymentCodes.Count());
|
||||
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count());
|
||||
|
||||
@@ -2733,7 +2733,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
Assert.EndsWith($"/i/{newInvoice.Id}", newInvoice.CheckoutLink);
|
||||
var controller = tester.PayTester.GetController<UIInvoiceController>(user.UserId, user.StoreId);
|
||||
var model = (PaymentModel)((ViewResult)await controller.Checkout(newInvoice.Id)).Model;
|
||||
var model = (CheckoutModel)((ViewResult)await controller.Checkout(newInvoice.Id)).Model;
|
||||
Assert.Equal("it-IT", model.DefaultLang);
|
||||
Assert.Equal("http://toto.com/lol", model.MerchantRefLink);
|
||||
|
||||
|
||||
@@ -3264,6 +3264,7 @@ namespace BTCPayServer.Tests
|
||||
public async Task CanUseLNAddress()
|
||||
{
|
||||
using var s = CreateSeleniumTester();
|
||||
s.Server.DeleteStore = false;
|
||||
s.Server.ActivateLightning();
|
||||
await s.StartAsync();
|
||||
await s.Server.EnsureChannelsSetup();
|
||||
@@ -3416,7 +3417,13 @@ namespace BTCPayServer.Tests
|
||||
var succ = JsonConvert.DeserializeObject<LNURLPayRequest.LNURLPayRequestCallbackResponse>(str);
|
||||
Assert.NotNull(succ.Pr);
|
||||
Assert.Equal(new LightMoney(2001), BOLT11PaymentRequest.Parse(succ.Pr, Network.RegTest).MinimumAmount);
|
||||
await s.Server.CustomerLightningD.Pay(succ.Pr);
|
||||
}
|
||||
|
||||
// Can we find our comment and address in the payment list?
|
||||
s.GoToInvoices();
|
||||
var source = s.Driver.PageSource;
|
||||
Assert.Contains(lnUsername, source);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -609,9 +609,7 @@ retry:
|
||||
var methods = await client.GetInvoicePaymentMethods(StoreId, invoiceId);
|
||||
var method = methods.First(m => m.PaymentMethodId == $"{cryptoCode}-LN");
|
||||
var bolt11 = method.Destination;
|
||||
TestLogs.LogInformation("PAYING");
|
||||
await parent.CustomerLightningD.Pay(bolt11);
|
||||
TestLogs.LogInformation("PAID");
|
||||
await WaitInvoicePaid(invoiceId);
|
||||
}
|
||||
|
||||
|
||||
@@ -1587,14 +1587,14 @@ namespace BTCPayServer.Tests
|
||||
ItemDesc = "Some description",
|
||||
FullNotifications = true
|
||||
}, Facade.Merchant);
|
||||
var checkout = (await user.GetController<UIInvoiceController>().Checkout(invoice.Id)).AssertViewModel<PaymentModel>();
|
||||
var checkout = (await user.GetController<UIInvoiceController>().Checkout(invoice.Id)).AssertViewModel<CheckoutModel>();
|
||||
Assert.Equal(lnMethod, checkout.PaymentMethodId);
|
||||
|
||||
// If we change store's default, it should change the checkout's default
|
||||
vm.DefaultPaymentMethod = btcMethod;
|
||||
Assert.IsType<RedirectToActionResult>(user.GetController<UIStoresController>().CheckoutAppearance(vm)
|
||||
.Result);
|
||||
checkout = (await user.GetController<UIInvoiceController>().Checkout(invoice.Id)).AssertViewModel<PaymentModel>();
|
||||
checkout = (await user.GetController<UIInvoiceController>().Checkout(invoice.Id)).AssertViewModel<CheckoutModel>();
|
||||
Assert.Equal(btcMethod, checkout.PaymentMethodId);
|
||||
}
|
||||
|
||||
@@ -1625,7 +1625,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
// validate that invoice data model doesn't have lightning string initially
|
||||
var res = await user.GetController<UIInvoiceController>().Checkout(invoice.Id);
|
||||
var paymentMethodFirst = Assert.IsType<PaymentModel>(
|
||||
var paymentMethodFirst = Assert.IsType<CheckoutModel>(
|
||||
Assert.IsType<ViewResult>(res).Model
|
||||
);
|
||||
Assert.DoesNotContain("&lightning=", paymentMethodFirst.InvoiceBitcoinUrlQR);
|
||||
@@ -1641,7 +1641,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
// validate that QR code now has both onchain and offchain payment urls
|
||||
res = await user.GetController<UIInvoiceController>().Checkout(invoice.Id);
|
||||
var paymentMethodUnified = Assert.IsType<PaymentModel>(
|
||||
var paymentMethodUnified = Assert.IsType<CheckoutModel>(
|
||||
Assert.IsType<ViewResult>(res).Model
|
||||
);
|
||||
Assert.StartsWith("bitcoin:bcrt", paymentMethodUnified.InvoiceBitcoinUrl);
|
||||
@@ -1655,8 +1655,8 @@ namespace BTCPayServer.Tests
|
||||
|
||||
// Standard for all uppercase characters in QR codes is still not implemented in all wallets
|
||||
// But we're proceeding with BECH32 being uppercase
|
||||
Assert.Equal($"bitcoin:{paymentMethodUnified.BtcAddress}", paymentMethodUnified.InvoiceBitcoinUrl.Split('?')[0]);
|
||||
Assert.Equal($"bitcoin:{paymentMethodUnified.BtcAddress.ToUpperInvariant()}", paymentMethodUnified.InvoiceBitcoinUrlQR.Split('?')[0]);
|
||||
Assert.Equal($"bitcoin:{paymentMethodUnified.Address}", paymentMethodUnified.InvoiceBitcoinUrl.Split('?')[0]);
|
||||
Assert.Equal($"bitcoin:{paymentMethodUnified.Address.ToUpperInvariant()}", paymentMethodUnified.InvoiceBitcoinUrlQR.Split('?')[0]);
|
||||
|
||||
// Fallback lightning invoice should be uppercase inside the QR code, lowercase in payment URI
|
||||
var lightningFallback = paymentMethodUnified.InvoiceBitcoinUrl.Split(new[] { "&lightning=" }, StringSplitOptions.None)[1];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@using BTCPayServer.Payments
|
||||
@model BTCPayServer.Components.InvoiceStatus.InvoiceStatusViewModel
|
||||
@inject Dictionary<PaymentMethodId, IPaymentModelExtension> Extensions
|
||||
@inject Dictionary<PaymentMethodId, ICheckoutModelExtension> Extensions
|
||||
|
||||
@{
|
||||
var state = Model.State.ToString();
|
||||
|
||||
@@ -68,7 +68,7 @@ public class StoreRecentInvoices : ViewComponent
|
||||
Details = new InvoiceDetailsModel
|
||||
{
|
||||
Archived = invoice.Archived,
|
||||
Payments = invoice.GetPayments(false)
|
||||
Payments = invoice.GetPayments(false)
|
||||
}
|
||||
}).ToList();
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ namespace BTCPayServer.Controllers
|
||||
StoreLink = Url.Action(nameof(UIStoresController.GeneralSettings), "UIStores", new { storeId = store.Id }),
|
||||
PaymentRequestLink = Url.Action(nameof(UIPaymentRequestController.ViewPaymentRequest), "UIPaymentRequest", new { payReqId = invoice.Metadata.PaymentRequestId }),
|
||||
Id = invoice.Id,
|
||||
Entity = invoice,
|
||||
State = invoiceState,
|
||||
TransactionSpeed = invoice.SpeedPolicy == SpeedPolicy.HighSpeed ? "high" :
|
||||
invoice.SpeedPolicy == SpeedPolicy.MediumSpeed ? "medium" :
|
||||
@@ -554,6 +555,7 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
Archived = invoice.Archived,
|
||||
Payments = invoice.GetPayments(false),
|
||||
Entity = invoice,
|
||||
CryptoPayments = invoice.GetPaymentPrompts().Select(
|
||||
data =>
|
||||
{
|
||||
@@ -692,7 +694,7 @@ namespace BTCPayServer.Controllers
|
||||
if (invoiceId is null)
|
||||
return NotFound();
|
||||
|
||||
var model = await GetInvoiceModel(invoiceId, paymentMethodId == null ? null : PaymentMethodId.Parse(paymentMethodId), lang);
|
||||
var model = await GetCheckoutModel(invoiceId, paymentMethodId == null ? null : PaymentMethodId.Parse(paymentMethodId), lang);
|
||||
if (model == null)
|
||||
{
|
||||
// see if the invoice actually exists and is in a state for which we do not display the checkout
|
||||
@@ -711,22 +713,7 @@ namespace BTCPayServer.Controllers
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpGet("invoice-noscript")]
|
||||
public async Task<IActionResult> CheckoutNoScript(string? invoiceId, string? id = null, string? paymentMethodId = null, [FromQuery] string? lang = null)
|
||||
{
|
||||
//Keep compatibility with Bitpay
|
||||
invoiceId = invoiceId ?? id;
|
||||
//
|
||||
if (invoiceId is null)
|
||||
return NotFound();
|
||||
var model = await GetInvoiceModel(invoiceId, paymentMethodId is null ? null : PaymentMethodId.Parse(paymentMethodId), lang);
|
||||
if (model == null)
|
||||
return NotFound();
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
private async Task<PaymentModel?> GetInvoiceModel(string invoiceId, PaymentMethodId? paymentMethodId, string? lang)
|
||||
private async Task<CheckoutModel?> GetCheckoutModel(string invoiceId, PaymentMethodId? paymentMethodId, string? lang)
|
||||
{
|
||||
var invoice = await _InvoiceRepository.GetInvoice(invoiceId);
|
||||
if (invoice == null)
|
||||
@@ -739,7 +726,7 @@ namespace BTCPayServer.Controllers
|
||||
bool isDefaultPaymentId = false;
|
||||
var storeBlob = store.GetStoreBlob();
|
||||
|
||||
var displayedPaymentMethods = invoice.GetPaymentPrompts().Select(p => p.PaymentMethodId).ToList();
|
||||
var displayedPaymentMethods = invoice.GetPaymentPrompts().Select(p => p.PaymentMethodId).ToHashSet();
|
||||
|
||||
|
||||
var btcId = PaymentTypes.CHAIN.GetPaymentMethodId("BTC");
|
||||
@@ -835,7 +822,7 @@ namespace BTCPayServer.Controllers
|
||||
if (prompt is null)
|
||||
return null;
|
||||
if (activated)
|
||||
return await GetInvoiceModel(invoiceId, paymentMethodId, lang);
|
||||
return await GetCheckoutModel(invoiceId, paymentMethodId, lang);
|
||||
|
||||
var accounting = prompt.Calculate();
|
||||
|
||||
@@ -876,11 +863,11 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
|
||||
string ShowMoney(decimal value) => MoneyExtensions.ShowMoney(value, prompt.RateDivisibility ?? prompt.Divisibility);
|
||||
var model = new PaymentModel
|
||||
var model = new CheckoutModel
|
||||
{
|
||||
Activated = prompt.Activated,
|
||||
PaymentMethodName = _prettyName.PrettyName(paymentMethodId),
|
||||
CryptoCode = prompt.Currency,
|
||||
PaymentMethodCurrency = prompt.Currency,
|
||||
RootPath = Request.PathBase.Value.WithTrailingSlash(),
|
||||
OrderId = orderId,
|
||||
InvoiceId = invoiceId,
|
||||
@@ -892,9 +879,9 @@ namespace BTCPayServer.Controllers
|
||||
CelebratePayment = storeBlob.CelebratePayment,
|
||||
OnChainWithLnInvoiceFallback = storeBlob.OnChainWithLnInvoiceFallback,
|
||||
CryptoImage = Request.GetRelativePathOrAbsolute(GetPaymentMethodImage(paymentMethodId)),
|
||||
BtcAddress = prompt.Destination,
|
||||
BtcDue = ShowMoney(accounting.Due),
|
||||
BtcPaid = ShowMoney(accounting.Paid),
|
||||
Address = prompt.Destination,
|
||||
Due = ShowMoney(accounting.Due),
|
||||
Paid = ShowMoney(accounting.Paid),
|
||||
InvoiceCurrency = invoice.Currency,
|
||||
// The Tweak is part of the PaymentMethodFee, but let's not show it in the UI as it's negligible.
|
||||
OrderAmount = ShowMoney(accounting.TotalDue - (prompt.PaymentMethodFee - prompt.TweakFee)),
|
||||
@@ -922,45 +909,31 @@ namespace BTCPayServer.Controllers
|
||||
Status = invoice.Status.ToString(),
|
||||
// The Tweak is part of the PaymentMethodFee, but let's not show it in the UI as it's negligible.
|
||||
NetworkFee = prompt.PaymentMethodFee - prompt.TweakFee,
|
||||
IsMultiCurrency = invoice.GetPayments(false).Select(p => p.PaymentMethodId).Concat(new[] { prompt.PaymentMethodId }).Distinct().Count() > 1,
|
||||
StoreId = store.Id,
|
||||
AvailableCryptos = invoice.GetPaymentPrompts()
|
||||
AvailablePaymentMethods = invoice.GetPaymentPrompts()
|
||||
.Select(kv =>
|
||||
{
|
||||
var handler = _handlers[kv.PaymentMethodId];
|
||||
return new PaymentModel.AvailableCrypto
|
||||
return new CheckoutModel.AvailablePaymentMethod
|
||||
{
|
||||
Displayed = displayedPaymentMethods.Contains(kv.PaymentMethodId),
|
||||
PaymentMethodId = kv.PaymentMethodId.ToString(),
|
||||
CryptoCode = kv.Currency,
|
||||
PaymentMethodId = kv.PaymentMethodId,
|
||||
PaymentMethodName = _prettyName.PrettyName(kv.PaymentMethodId),
|
||||
IsLightning = handler is ILightningPaymentHandler,
|
||||
CryptoImage = Request.GetRelativePathOrAbsolute(GetPaymentMethodImage(kv.PaymentMethodId)),
|
||||
Link = Url.Action(nameof(Checkout),
|
||||
new
|
||||
{
|
||||
invoiceId,
|
||||
paymentMethodId = kv.PaymentMethodId.ToString()
|
||||
})
|
||||
Order = kv.PaymentMethodId switch
|
||||
{
|
||||
_ when PaymentTypes.CHAIN.GetPaymentMethodId(_NetworkProvider.DefaultNetwork.CryptoCode) == kv.PaymentMethodId => 0,
|
||||
_ when PaymentTypes.LN.GetPaymentMethodId(_NetworkProvider.DefaultNetwork.CryptoCode) == kv.PaymentMethodId => 1,
|
||||
_ when handler is ILightningPaymentHandler => 2,
|
||||
_ => 3
|
||||
}
|
||||
};
|
||||
}).Where(c => c.CryptoImage != "/")
|
||||
.OrderByDescending(a => a.CryptoCode == _NetworkProvider.DefaultNetwork.CryptoCode).ThenBy(a => a.PaymentMethodName).ThenBy(a => a.IsLightning ? 1 : 0)
|
||||
})
|
||||
.OrderBy(a => a.Order)
|
||||
.ToList()
|
||||
};
|
||||
if (_paymentModelExtensions.TryGetValue(paymentMethodId, out var extension))
|
||||
extension.ModifyPaymentModel(new PaymentModelContext(model, store, storeBlob, invoice, Url, prompt, handler));
|
||||
model.UISettings = _viewProvider.TryGetViewViewModel(prompt, "CheckoutUI")?.View as CheckoutUIPaymentMethodSettings;
|
||||
model.PaymentMethodId = paymentMethodId.ToString();
|
||||
model.OrderAmountFiat = OrderAmountFromInvoice(model.CryptoCode, invoice, DisplayFormatter.CurrencyFormat.Symbol);
|
||||
|
||||
foreach (var paymentPrompt in invoice.GetPaymentPrompts())
|
||||
{
|
||||
var vvm = _viewProvider.TryGetViewViewModel(paymentPrompt, "CheckoutUI");
|
||||
if (vvm?.View is CheckoutUIPaymentMethodSettings { ExtensionPartial: { } partial })
|
||||
{
|
||||
model.ExtensionPartials.Add(partial);
|
||||
}
|
||||
}
|
||||
model.PaymentMethodId = paymentMethodId.ToString();
|
||||
model.OrderAmountFiat = OrderAmountFromInvoice(model.PaymentMethodCurrency, invoice, DisplayFormatter.CurrencyFormat.Symbol);
|
||||
|
||||
if (storeBlob.PlaySoundOnPayment)
|
||||
{
|
||||
@@ -973,6 +946,12 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
var expiration = TimeSpan.FromSeconds(model.ExpirationSeconds);
|
||||
model.TimeLeft = expiration.PrettyPrint();
|
||||
|
||||
if (_paymentModelExtensions.TryGetValue(paymentMethodId, out var extension) &&
|
||||
_handlers.TryGetValue(paymentMethodId, out var h))
|
||||
{
|
||||
extension.ModifyCheckoutModel(new CheckoutModelContext(model, store, storeBlob, invoice, Url, prompt, h));
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -1008,7 +987,7 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
if (string.IsNullOrEmpty(paymentMethodId))
|
||||
paymentMethodId = implicitPaymentMethodId;
|
||||
var model = await GetInvoiceModel(invoiceId, paymentMethodId == null ? null : PaymentMethodId.Parse(paymentMethodId), lang);
|
||||
var model = await GetCheckoutModel(invoiceId, paymentMethodId == null ? null : PaymentMethodId.Parse(paymentMethodId), lang);
|
||||
if (model == null)
|
||||
return NotFound();
|
||||
return Json(model);
|
||||
|
||||
@@ -62,8 +62,7 @@ namespace BTCPayServer.Controllers
|
||||
private readonly LinkGenerator _linkGenerator;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly TransactionLinkProviders _transactionLinkProviders;
|
||||
private readonly Dictionary<PaymentMethodId, IPaymentModelExtension> _paymentModelExtensions;
|
||||
private readonly PaymentMethodViewProvider _viewProvider;
|
||||
private readonly Dictionary<PaymentMethodId, ICheckoutModelExtension> _paymentModelExtensions;
|
||||
private readonly PrettyNameProvider _prettyName;
|
||||
private readonly AppService _appService;
|
||||
private readonly IFileService _fileService;
|
||||
@@ -98,8 +97,7 @@ namespace BTCPayServer.Controllers
|
||||
DefaultRulesCollection defaultRules,
|
||||
IAuthorizationService authorizationService,
|
||||
TransactionLinkProviders transactionLinkProviders,
|
||||
Dictionary<PaymentMethodId, IPaymentModelExtension> paymentModelExtensions,
|
||||
PaymentMethodViewProvider viewProvider,
|
||||
Dictionary<PaymentMethodId, ICheckoutModelExtension> paymentModelExtensions,
|
||||
PrettyNameProvider prettyName)
|
||||
{
|
||||
_displayFormatter = displayFormatter;
|
||||
@@ -124,7 +122,6 @@ namespace BTCPayServer.Controllers
|
||||
_authorizationService = authorizationService;
|
||||
_transactionLinkProviders = transactionLinkProviders;
|
||||
_paymentModelExtensions = paymentModelExtensions;
|
||||
_viewProvider = viewProvider;
|
||||
_prettyName = prettyName;
|
||||
_fileService = fileService;
|
||||
_uriResolver = uriResolver;
|
||||
|
||||
@@ -21,13 +21,13 @@ namespace BTCPayServer.Controllers
|
||||
public class UIPublicLightningNodeInfoController : Controller
|
||||
{
|
||||
private readonly BTCPayNetworkProvider _BtcPayNetworkProvider;
|
||||
private readonly Dictionary<PaymentMethodId, IPaymentModelExtension> _paymentModelExtensions;
|
||||
private readonly Dictionary<PaymentMethodId, ICheckoutModelExtension> _paymentModelExtensions;
|
||||
private readonly UriResolver _uriResolver;
|
||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||
private readonly StoreRepository _StoreRepository;
|
||||
|
||||
public UIPublicLightningNodeInfoController(BTCPayNetworkProvider btcPayNetworkProvider,
|
||||
Dictionary<PaymentMethodId, IPaymentModelExtension> paymentModelExtensions,
|
||||
Dictionary<PaymentMethodId, ICheckoutModelExtension> paymentModelExtensions,
|
||||
UriResolver uriResolver,
|
||||
PaymentMethodHandlerDictionary handlers,
|
||||
StoreRepository storeRepository)
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace BTCPayServer.Controllers
|
||||
private readonly LabelService _labelService;
|
||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||
private readonly DefaultRulesCollection _defaultRules;
|
||||
private readonly Dictionary<PaymentMethodId, IPaymentModelExtension> _paymentModelExtensions;
|
||||
private readonly Dictionary<PaymentMethodId, ICheckoutModelExtension> _paymentModelExtensions;
|
||||
private readonly TransactionLinkProviders _transactionLinkProviders;
|
||||
private readonly PullPaymentHostedService _pullPaymentHostedService;
|
||||
private readonly WalletHistogramService _walletHistogramService;
|
||||
@@ -98,7 +98,7 @@ namespace BTCPayServer.Controllers
|
||||
LabelService labelService,
|
||||
DefaultRulesCollection defaultRules,
|
||||
PaymentMethodHandlerDictionary handlers,
|
||||
Dictionary<PaymentMethodId, IPaymentModelExtension> paymentModelExtensions,
|
||||
Dictionary<PaymentMethodId, ICheckoutModelExtension> paymentModelExtensions,
|
||||
TransactionLinkProviders transactionLinkProviders)
|
||||
{
|
||||
_currencyTable = currencyTable;
|
||||
|
||||
@@ -14,6 +14,8 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Abstractions.Contracts;
|
||||
using BTCPayServer.Abstractions.Services;
|
||||
using BTCPayServer.BIP78.Sender;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Data;
|
||||
@@ -289,6 +291,14 @@ namespace BTCPayServer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static IServiceCollection AddUIExtension(this IServiceCollection services, string location, string partialViewName)
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
services.AddSingleton<IUIExtension>(new UIExtension(partialViewName, location));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
return services;
|
||||
}
|
||||
public static IServiceCollection AddReportProvider<T>(this IServiceCollection services)
|
||||
where T : ReportProvider
|
||||
{
|
||||
|
||||
@@ -158,8 +158,7 @@ namespace BTCPayServer.Hosting
|
||||
//
|
||||
|
||||
AddOnchainWalletParsers(services);
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Bitcoin/ViewBitcoinLikePaymentData", "store-invoices-payments"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Lightning/ViewLightningLikePaymentData", "store-invoices-payments"));
|
||||
|
||||
|
||||
services.AddStartupTask<BlockExplorerLinkStartupTask>();
|
||||
services.AddStartupTask<LoadCurrencyNameTableStartupTask>();
|
||||
@@ -365,6 +364,11 @@ namespace BTCPayServer.Hosting
|
||||
o.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(DerivationStrategyBase)));
|
||||
});
|
||||
|
||||
services.AddUIExtension("checkout-end", "Bitcoin/BitcoinLikeMethodCheckout");
|
||||
services.AddUIExtension("checkout-end", "Lightning/LightningLikeMethodCheckout");
|
||||
services.AddUIExtension("store-invoices-payments", "Bitcoin/ViewBitcoinLikePaymentData");
|
||||
services.AddUIExtension("store-invoices-payments", "Lightning/ViewLightningLikePaymentData");
|
||||
|
||||
services.AddSingleton<Services.NBXplorerConnectionFactory>();
|
||||
services.AddSingleton<IHostedService, Services.NBXplorerConnectionFactory>(o => o.GetRequiredService<Services.NBXplorerConnectionFactory>());
|
||||
services.AddSingleton<HostedServices.CheckConfigurationHostedService>();
|
||||
@@ -386,8 +390,8 @@ namespace BTCPayServer.Hosting
|
||||
o.GetRequiredService<IEnumerable<IPaymentMethodBitpayAPIExtension>>().ToDictionary(o => o.PaymentMethodId, o => o));
|
||||
services.AddSingleton<Dictionary<PaymentMethodId, IPaymentLinkExtension>>(o =>
|
||||
o.GetRequiredService<IEnumerable<IPaymentLinkExtension>>().ToDictionary(o => o.PaymentMethodId, o => o));
|
||||
services.AddSingleton<Dictionary<PaymentMethodId, IPaymentModelExtension>>(o =>
|
||||
o.GetRequiredService<IEnumerable<IPaymentModelExtension>>().ToDictionary(o => o.PaymentMethodId, o => o));
|
||||
services.AddSingleton<Dictionary<PaymentMethodId, ICheckoutModelExtension>>(o =>
|
||||
o.GetRequiredService<IEnumerable<ICheckoutModelExtension>>().ToDictionary(o => o.PaymentMethodId, o => o));
|
||||
|
||||
services.AddHttpClient(LightningLikePayoutHandler.LightningLikePayoutHandlerOnionNamedClient)
|
||||
.ConfigurePrimaryHttpMessageHandler<Socks5HttpClientHandler>();
|
||||
@@ -398,13 +402,11 @@ o.GetRequiredService<IEnumerable<IPaymentLinkExtension>>().ToDictionary(o => o.P
|
||||
services.AddSingleton<IHostedService, NBXplorerListener>();
|
||||
|
||||
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("LNURL/LightningAddressNav",
|
||||
"store-integrations-nav"));
|
||||
services.AddUIExtension("store-integrations-nav", "LNURL/LightningAddressNav");
|
||||
services.AddSingleton<IHostedService, LightningListener>();
|
||||
services.AddSingleton<IHostedService, LightningPendingPayoutListener>();
|
||||
|
||||
services.AddSingleton<PaymentMethodHandlerDictionary>();
|
||||
services.AddSingleton<PaymentMethodViewProvider>();
|
||||
|
||||
services.AddSingleton<PayoutMethodHandlerDictionary>();
|
||||
|
||||
@@ -627,12 +629,10 @@ o.GetRequiredService<IEnumerable<IPaymentLinkExtension>>().ToDictionary(o => o.P
|
||||
(BitcoinLikePaymentHandler)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinLikePaymentHandler), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentLinkExtension>(provider =>
|
||||
(IPaymentLinkExtension)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinPaymentLinkExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentModelExtension>(provider =>
|
||||
(BitcoinPaymentModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinPaymentModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<ICheckoutModelExtension>(provider =>
|
||||
(BitcoinCheckoutModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinCheckoutModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentMethodBitpayAPIExtension>(provider =>
|
||||
(IPaymentMethodBitpayAPIExtension)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinPaymentMethodBitpayAPIExtension), new object[] { pmi }));
|
||||
services.AddSingleton<IPaymentMethodViewExtension>(provider =>
|
||||
(IPaymentMethodViewExtension)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinPaymentMethodViewExtension), new object[] { pmi }));
|
||||
|
||||
if (!network.ReadonlyWallet && network.WalletSupported)
|
||||
{
|
||||
@@ -650,10 +650,8 @@ o.GetRequiredService<IEnumerable<IPaymentLinkExtension>>().ToDictionary(o => o.P
|
||||
(LightningLikePaymentHandler)ActivatorUtilities.CreateInstance(provider, typeof(LightningLikePaymentHandler), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentLinkExtension>(provider =>
|
||||
(IPaymentLinkExtension)ActivatorUtilities.CreateInstance(provider, typeof(LightningPaymentLinkExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentModelExtension>(provider =>
|
||||
(IPaymentModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(LightningPaymentModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentMethodViewExtension>(provider =>
|
||||
(IPaymentMethodViewExtension)ActivatorUtilities.CreateInstance(provider, typeof(LightningPaymentMethodViewExtension), new object[] { pmi }));
|
||||
services.AddSingleton<ICheckoutModelExtension>(provider =>
|
||||
(ICheckoutModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(LNCheckoutModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentMethodBitpayAPIExtension>(provider =>
|
||||
(IPaymentMethodBitpayAPIExtension)ActivatorUtilities.CreateInstance(provider, typeof(LightningPaymentMethodBitpayAPIExtension), new object[] { pmi }));
|
||||
var payoutMethodId = PayoutTypes.LN.GetPayoutMethodId(network.CryptoCode);
|
||||
@@ -667,10 +665,8 @@ o.GetRequiredService<IEnumerable<IPaymentLinkExtension>>().ToDictionary(o => o.P
|
||||
(LNURLPayPaymentHandler)ActivatorUtilities.CreateInstance(provider, typeof(LNURLPayPaymentHandler), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentLinkExtension>(provider =>
|
||||
(IPaymentLinkExtension)ActivatorUtilities.CreateInstance(provider, typeof(LNURLPayPaymentLinkExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentModelExtension>(provider =>
|
||||
(IPaymentModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(LNURLPayPaymentModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentMethodViewExtension>(provider =>
|
||||
(IPaymentMethodViewExtension)ActivatorUtilities.CreateInstance(provider, typeof(LNURLPaymentMethodViewExtension), new object[] { pmi }));
|
||||
services.AddSingleton<ICheckoutModelExtension>(provider =>
|
||||
(ICheckoutModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(LNURLCheckoutModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentMethodBitpayAPIExtension>(provider =>
|
||||
(IPaymentMethodBitpayAPIExtension)ActivatorUtilities.CreateInstance(provider, typeof(LNURLPayPaymentMethodBitpayAPIExtension), new object[] { pmi }));
|
||||
}
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.Client.Models;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using BTCPayServer.Payments;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Models.InvoicingModels
|
||||
{
|
||||
public class PaymentModel
|
||||
public class CheckoutModel
|
||||
{
|
||||
public CheckoutUIPaymentMethodSettings UISettings;
|
||||
public class AvailableCrypto
|
||||
public string CheckoutBodyComponentName { get; set; }
|
||||
public class AvailablePaymentMethod
|
||||
{
|
||||
public string PaymentMethodId { get; set; }
|
||||
public string CryptoImage { get; set; }
|
||||
public string Link { get; set; }
|
||||
public string PaymentMethodName { get; set; }
|
||||
public bool IsLightning { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
[JsonConverter(typeof(PaymentMethodIdJsonConverter))]
|
||||
public PaymentMethodId PaymentMethodId { get; set; }
|
||||
public bool Displayed { get; set; }
|
||||
public string PaymentMethodName { get; set; }
|
||||
public int Order { get; set; }
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, JToken> AdditionalData { get; set; } = new();
|
||||
}
|
||||
public StoreBrandingViewModel StoreBranding { get; set; }
|
||||
public string PaymentSoundUrl { get; set; }
|
||||
@@ -26,15 +29,15 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
public string DefaultLang { get; set; }
|
||||
public bool ShowPayInWalletButton { get; set; }
|
||||
public bool ShowStoreHeader { get; set; }
|
||||
public List<AvailableCrypto> AvailableCryptos { get; set; } = new();
|
||||
public List<AvailablePaymentMethod> AvailablePaymentMethods { get; set; } = new();
|
||||
public bool IsModal { get; set; }
|
||||
public bool IsUnsetTopUp { get; set; }
|
||||
public bool OnChainWithLnInvoiceFallback { get; set; }
|
||||
public bool CelebratePayment { get; set; }
|
||||
public string CryptoCode { get; set; }
|
||||
public string PaymentMethodCurrency { get; set; }
|
||||
public string InvoiceId { get; set; }
|
||||
public string BtcAddress { get; set; }
|
||||
public string BtcDue { get; set; }
|
||||
public string Address { get; set; }
|
||||
public string Due { get; set; }
|
||||
public string CustomerEmail { get; set; }
|
||||
public bool ShowRecommendedFee { get; set; }
|
||||
public decimal FeeRate { get; set; }
|
||||
@@ -53,12 +56,11 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
public string InvoiceBitcoinUrlQR { get; set; }
|
||||
public int TxCount { get; set; }
|
||||
public int TxCountForFee { get; set; }
|
||||
public string BtcPaid { get; set; }
|
||||
public string Paid { get; set; }
|
||||
public string StoreSupportUrl { get; set; }
|
||||
|
||||
public string OrderId { get; set; }
|
||||
public decimal NetworkFee { get; set; }
|
||||
public bool IsMultiCurrency { get; set; }
|
||||
public int MaxTimeMinutes { get; set; }
|
||||
public string PaymentMethodId { get; set; }
|
||||
public string PaymentMethodName { get; set; }
|
||||
@@ -72,7 +74,7 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
public string ReceiptLink { get; set; }
|
||||
public int? RequiredConfirmations { get; set; }
|
||||
public long? ReceivedConfirmations { get; set; }
|
||||
|
||||
public HashSet<string> ExtensionPartials { get; } = new HashSet<string>();
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, JToken> AdditionalData { get; set; } = new();
|
||||
}
|
||||
}
|
||||
@@ -136,5 +136,6 @@ namespace BTCPayServer.Models.InvoicingModels
|
||||
public bool HasRefund { get; set; }
|
||||
public bool StillDue { get; set; }
|
||||
public bool HasRates { get; set; }
|
||||
public InvoiceEntity Entity { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ using NBitcoin.DataEncoders;
|
||||
|
||||
namespace BTCPayServer.Payments.Bitcoin
|
||||
{
|
||||
public class BitcoinPaymentModelExtension : IPaymentModelExtension
|
||||
public class BitcoinCheckoutModelExtension : ICheckoutModelExtension
|
||||
{
|
||||
public const string CheckoutBodyComponentName = "BitcoinCheckoutBody";
|
||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||
private readonly BTCPayNetwork _Network;
|
||||
private readonly DisplayFormatter _displayFormatter;
|
||||
@@ -22,7 +23,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
private readonly IPaymentLinkExtension? lnurlPaymentLinkExtension;
|
||||
private readonly string? _bech32Prefix;
|
||||
|
||||
public BitcoinPaymentModelExtension(
|
||||
public BitcoinCheckoutModelExtension(
|
||||
PaymentMethodId paymentMethodId,
|
||||
BTCPayNetwork network,
|
||||
IEnumerable<IPaymentLinkExtension> paymentLinkExtensions,
|
||||
@@ -44,18 +45,19 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
public string Image => _Network.CryptoImagePath;
|
||||
public string Badge => "";
|
||||
public PaymentMethodId PaymentMethodId { get; }
|
||||
public void ModifyPaymentModel(PaymentModelContext context)
|
||||
public void ModifyCheckoutModel(CheckoutModelContext context)
|
||||
{
|
||||
var prompt = context.Prompt;
|
||||
if (!_handlers.TryGetValue(PaymentMethodId, out var o) || o is not BitcoinLikePaymentHandler handler)
|
||||
if (context is not { Handler: BitcoinLikePaymentHandler handler})
|
||||
return;
|
||||
var prompt = context.Prompt;
|
||||
var details = handler.ParsePaymentPromptDetails(prompt.Details);
|
||||
context.Model.CheckoutBodyComponentName = CheckoutBodyComponentName;
|
||||
context.Model.ShowRecommendedFee = context.StoreBlob.ShowRecommendedFee;
|
||||
context.Model.FeeRate = details.RecommendedFeeRate.SatoshiPerByte;
|
||||
|
||||
|
||||
var bip21Case = _Network.SupportLightning && context.StoreBlob.OnChainWithLnInvoiceFallback;
|
||||
var amountInSats = bip21Case && context.StoreBlob.LightningAmountInSatoshi && context.Model.CryptoCode == "BTC";
|
||||
var amountInSats = bip21Case && context.StoreBlob.LightningAmountInSatoshi && context.Model.PaymentMethodCurrency == "BTC";
|
||||
string? lightningFallback = null;
|
||||
if (context.Model.Activated && bip21Case)
|
||||
{
|
||||
@@ -117,10 +119,10 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
// model.InvoiceBitcoinUrlQR: bitcoin:bcrt1qxp2qa5dhn7?amount=0.00044007&lightning=LNBCRT4400...
|
||||
}
|
||||
|
||||
if (_Network.CryptoCode.Equals("BTC", StringComparison.InvariantCultureIgnoreCase) && _bech32Prefix is not null && context.Model.BtcAddress.StartsWith(_bech32Prefix, StringComparison.OrdinalIgnoreCase))
|
||||
if (_Network.CryptoCode.Equals("BTC", StringComparison.InvariantCultureIgnoreCase) && _bech32Prefix is not null && context.Model.Address.StartsWith(_bech32Prefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
context.Model.InvoiceBitcoinUrlQR = context.Model.InvoiceBitcoinUrlQR.Replace(
|
||||
$"{_Network.NBitcoinNetwork.UriScheme}:{context.Model.BtcAddress}", $"{_Network.NBitcoinNetwork.UriScheme}:{context.Model.BtcAddress.ToUpperInvariant()}",
|
||||
$"{_Network.NBitcoinNetwork.UriScheme}:{context.Model.Address}", $"{_Network.NBitcoinNetwork.UriScheme}:{context.Model.Address.ToUpperInvariant()}",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
// model.InvoiceBitcoinUrlQR: bitcoin:BCRT1QXP2QA5DHN...?amount=0.00044007&lightning=LNBCRT4400...
|
||||
}
|
||||
@@ -136,15 +138,15 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
}
|
||||
}
|
||||
|
||||
public static void PreparePaymentModelForAmountInSats(PaymentModel model, decimal rate, DisplayFormatter displayFormatter)
|
||||
public static void PreparePaymentModelForAmountInSats(CheckoutModel model, decimal rate, DisplayFormatter displayFormatter)
|
||||
{
|
||||
var satoshiCulture = new CultureInfo(CultureInfo.InvariantCulture.Name)
|
||||
{
|
||||
NumberFormat = { NumberGroupSeparator = " " }
|
||||
};
|
||||
model.CryptoCode = "sats";
|
||||
model.BtcDue = Money.Parse(model.BtcDue).ToUnit(MoneyUnit.Satoshi).ToString("N0", satoshiCulture);
|
||||
model.BtcPaid = Money.Parse(model.BtcPaid).ToUnit(MoneyUnit.Satoshi).ToString("N0", satoshiCulture);
|
||||
model.PaymentMethodCurrency = "sats";
|
||||
model.Due = Money.Parse(model.Due).ToUnit(MoneyUnit.Satoshi).ToString("N0", satoshiCulture);
|
||||
model.Paid = Money.Parse(model.Paid).ToUnit(MoneyUnit.Satoshi).ToString("N0", satoshiCulture);
|
||||
model.OrderAmount = Money.Parse(model.OrderAmount).ToUnit(MoneyUnit.Satoshi).ToString("N0", satoshiCulture);
|
||||
model.NetworkFee = new Money(model.NetworkFee, MoneyUnit.BTC).ToUnit(MoneyUnit.Satoshi);
|
||||
model.Rate = model.InvoiceCurrency is "BTC" or "SATS"
|
||||
@@ -1,22 +0,0 @@
|
||||
namespace BTCPayServer.Payments.Bitcoin
|
||||
{
|
||||
public class BitcoinPaymentMethodViewExtension : IPaymentMethodViewExtension
|
||||
{
|
||||
public BitcoinPaymentMethodViewExtension(PaymentMethodId paymentMethodId)
|
||||
{
|
||||
PaymentMethodId = paymentMethodId;
|
||||
}
|
||||
public PaymentMethodId PaymentMethodId { get; }
|
||||
|
||||
public void RegisterViews(PaymentMethodViewContext context)
|
||||
{
|
||||
context.RegisterCheckoutUI(new CheckoutUIPaymentMethodSettings
|
||||
{
|
||||
ExtensionPartial = "Bitcoin/BitcoinLikeMethodCheckout",
|
||||
CheckoutBodyVueComponentName = "BitcoinLikeMethodCheckout",
|
||||
CheckoutHeaderVueComponentName = "BitcoinLikeMethodCheckoutHeader",
|
||||
NoScriptPartialName = "Bitcoin/BitcoinLikeMethodCheckoutNoScript"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,20 +4,20 @@ using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace BTCPayServer.Payments
|
||||
{
|
||||
public record PaymentModelContext(
|
||||
PaymentModel Model,
|
||||
public record CheckoutModelContext(
|
||||
CheckoutModel Model,
|
||||
Data.StoreData Store,
|
||||
Data.StoreBlob StoreBlob,
|
||||
InvoiceEntity InvoiceEntity,
|
||||
IUrlHelper UrlHelper,
|
||||
PaymentPrompt Prompt,
|
||||
IPaymentMethodHandler Handler);
|
||||
public interface IPaymentModelExtension
|
||||
public interface ICheckoutModelExtension
|
||||
{
|
||||
public PaymentMethodId PaymentMethodId { get; }
|
||||
string DisplayName { get; }
|
||||
string Image { get; }
|
||||
string Badge { get; }
|
||||
void ModifyPaymentModel(PaymentModelContext context);
|
||||
void ModifyCheckoutModel(CheckoutModelContext context);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
|
||||
namespace BTCPayServer.Payments
|
||||
{
|
||||
public interface IPaymentMethodViewExtension
|
||||
{
|
||||
PaymentMethodId PaymentMethodId { get; }
|
||||
void RegisterViews(PaymentMethodViewContext context);
|
||||
}
|
||||
public record ViewViewModel(object View, object ViewModel);
|
||||
public class PaymentMethodViewProvider
|
||||
{
|
||||
private readonly Dictionary<PaymentMethodId, IPaymentMethodViewExtension> _extensions;
|
||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||
|
||||
public PaymentMethodViewProvider(
|
||||
IEnumerable<IPaymentMethodViewExtension> extensions,
|
||||
PaymentMethodHandlerDictionary handlers)
|
||||
{
|
||||
_extensions = extensions.ToDictionary(o => o.PaymentMethodId, o => o);
|
||||
_handlers = handlers;
|
||||
}
|
||||
public ViewViewModel? TryGetViewViewModel(PaymentPrompt paymentPrompt, string key)
|
||||
{
|
||||
if (!_extensions.TryGetValue(paymentPrompt.PaymentMethodId, out var extension))
|
||||
return null;
|
||||
if (!_handlers.TryGetValue(paymentPrompt.PaymentMethodId, out var handler) || paymentPrompt.Details is null)
|
||||
return null;
|
||||
var ctx = new PaymentMethodViewContext()
|
||||
{
|
||||
Details = handler.ParsePaymentPromptDetails(paymentPrompt.Details)
|
||||
};
|
||||
extension.RegisterViews(ctx);
|
||||
object? view = null;
|
||||
if (!ctx._Views.TryGetValue(key, out view))
|
||||
return null;
|
||||
return new ViewViewModel(view, handler.ParsePaymentPromptDetails(paymentPrompt.Details));
|
||||
}
|
||||
}
|
||||
public class PaymentMethodViewContext
|
||||
{
|
||||
internal Dictionary<string, object> _Views = new Dictionary<string, object>();
|
||||
|
||||
public object? Details { get; internal set; }
|
||||
|
||||
public void RegisterPaymentMethodDetails(string partialName)
|
||||
{
|
||||
_Views.Add("AdditionalPaymentMethodDetails", partialName);
|
||||
}
|
||||
public void RegisterCheckoutUI(CheckoutUIPaymentMethodSettings settings)
|
||||
{
|
||||
_Views.Add("CheckoutUI", settings);
|
||||
}
|
||||
public void Register(string key, object value)
|
||||
{
|
||||
_Views.Add(key, value);
|
||||
}
|
||||
}
|
||||
public class CheckoutUIPaymentMethodSettings
|
||||
{
|
||||
public string? ExtensionPartial { get; set; }
|
||||
public string? CheckoutBodyVueComponentName { get; set; }
|
||||
public string? CheckoutHeaderVueComponentName { get; set; }
|
||||
public string? NoScriptPartialName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ using NBitcoin;
|
||||
|
||||
namespace BTCPayServer.Payments.LNURLPay
|
||||
{
|
||||
public class LNURLPayPaymentModelExtension : IPaymentModelExtension
|
||||
public class LNURLCheckoutModelExtension : ICheckoutModelExtension
|
||||
{
|
||||
public LNURLPayPaymentModelExtension(
|
||||
public LNURLCheckoutModelExtension(
|
||||
PaymentMethodId paymentMethodId,
|
||||
BTCPayNetwork network,
|
||||
DisplayFormatter displayFormatter,
|
||||
@@ -37,19 +37,22 @@ namespace BTCPayServer.Payments.LNURLPay
|
||||
public string Badge => "⚡";
|
||||
|
||||
private const string UriScheme = "lightning:";
|
||||
public void ModifyPaymentModel(PaymentModelContext context)
|
||||
public void ModifyCheckoutModel(CheckoutModelContext context)
|
||||
{
|
||||
if (context is not { Handler: LNURLPayPaymentHandler handler })
|
||||
return;
|
||||
var lnurl = paymentLinkExtension.GetPaymentLink(context.Prompt, context.UrlHelper);
|
||||
if (lnurl is not null)
|
||||
{
|
||||
context.Model.BtcAddress = lnurl.Replace(UriScheme, "");
|
||||
context.Model.Address = lnurl.Replace(UriScheme, "");
|
||||
context.Model.InvoiceBitcoinUrl = lnurl;
|
||||
context.Model.InvoiceBitcoinUrlQR = lnurl.ToUpperInvariant().Replace(UriScheme.ToUpperInvariant(), UriScheme);
|
||||
}
|
||||
context.Model.CheckoutBodyComponentName = LNCheckoutModelExtension.CheckoutBodyComponentName;
|
||||
context.Model.PeerInfo = handler.ParsePaymentPromptDetails(context.Prompt.Details).NodeInfo;
|
||||
if (context.StoreBlob.LightningAmountInSatoshi && context.Model.CryptoCode == "BTC")
|
||||
if (context.StoreBlob.LightningAmountInSatoshi && context.Model.PaymentMethodCurrency == "BTC")
|
||||
{
|
||||
BitcoinPaymentModelExtension.PreparePaymentModelForAmountInSats(context.Model, context.Prompt.Rate, _displayFormatter);
|
||||
BitcoinCheckoutModelExtension.PreparePaymentModelForAmountInSats(context.Model, context.Prompt.Rate, _displayFormatter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace BTCPayServer.Payments.LNURLPay
|
||||
{
|
||||
public class LNURLPaymentMethodViewExtension : IPaymentMethodViewExtension
|
||||
{
|
||||
public LNURLPaymentMethodViewExtension(PaymentMethodId paymentMethodId)
|
||||
{
|
||||
PaymentMethodId = paymentMethodId;
|
||||
}
|
||||
public PaymentMethodId PaymentMethodId { get; }
|
||||
|
||||
public void RegisterViews(PaymentMethodViewContext context)
|
||||
{
|
||||
var details = context.Details;
|
||||
if (details is not LNURLPayPaymentMethodDetails d)
|
||||
return;
|
||||
context.RegisterPaymentMethodDetails("LNURL/AdditionalPaymentMethodDetails");
|
||||
context.RegisterCheckoutUI(new CheckoutUIPaymentMethodSettings()
|
||||
{
|
||||
ExtensionPartial = "Lightning/LightningLikeMethodCheckout",
|
||||
CheckoutBodyVueComponentName = "LightningLikeMethodCheckout",
|
||||
CheckoutHeaderVueComponentName = "LightningLikeMethodCheckoutHeader",
|
||||
NoScriptPartialName = "Lightning/LightningLikeMethodCheckoutNoScript"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,12 @@ using System.Linq;
|
||||
|
||||
namespace BTCPayServer.Payments.Lightning
|
||||
{
|
||||
public class LightningPaymentModelExtension : IPaymentModelExtension
|
||||
public class LNCheckoutModelExtension : ICheckoutModelExtension
|
||||
{
|
||||
public const string CheckoutBodyComponentName = "LightningCheckoutBody";
|
||||
private readonly DisplayFormatter _displayFormatter;
|
||||
IPaymentLinkExtension _PaymentLinkExtension;
|
||||
public LightningPaymentModelExtension(
|
||||
public LNCheckoutModelExtension(
|
||||
PaymentMethodId paymentMethodId,
|
||||
BTCPayNetwork network,
|
||||
DisplayFormatter displayFormatter,
|
||||
@@ -37,20 +38,21 @@ namespace BTCPayServer.Payments.Lightning
|
||||
|
||||
public string Image => Network.LightningImagePath;
|
||||
public string Badge => "⚡";
|
||||
public void ModifyPaymentModel(PaymentModelContext context)
|
||||
public void ModifyCheckoutModel(CheckoutModelContext context)
|
||||
{
|
||||
if (!Handlers.TryGetValue(PaymentMethodId, out var o) || o is not LightningLikePaymentHandler handler)
|
||||
if (context is not { Handler: LightningLikePaymentHandler handler })
|
||||
return;
|
||||
var paymentPrompt = context.InvoiceEntity.GetPaymentPrompt(PaymentMethodId);
|
||||
if (paymentPrompt is null)
|
||||
return;
|
||||
context.Model.CheckoutBodyComponentName = CheckoutBodyComponentName;
|
||||
context.Model.InvoiceBitcoinUrl = _PaymentLinkExtension.GetPaymentLink(context.Prompt, context.UrlHelper);
|
||||
if (context.Model.InvoiceBitcoinUrl is not null)
|
||||
context.Model.InvoiceBitcoinUrlQR = $"lightning:{context.Model.InvoiceBitcoinUrl.ToUpperInvariant()?.Substring("LIGHTNING:".Length)}";
|
||||
context.Model.PeerInfo = handler.ParsePaymentPromptDetails(paymentPrompt.Details).NodeInfo;
|
||||
if (context.StoreBlob.LightningAmountInSatoshi && context.Model.CryptoCode == "BTC")
|
||||
if (context.StoreBlob.LightningAmountInSatoshi && context.Model.PaymentMethodCurrency == "BTC")
|
||||
{
|
||||
BitcoinPaymentModelExtension.PreparePaymentModelForAmountInSats(context.Model, paymentPrompt.Rate, _displayFormatter);
|
||||
BitcoinCheckoutModelExtension.PreparePaymentModelForAmountInSats(context.Model, paymentPrompt.Rate, _displayFormatter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,9 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Payments.Lightning
|
||||
{
|
||||
public interface ILightningPaymentHandler : IHasNetwork
|
||||
public interface ILightningPaymentHandler : IHasNetwork, IPaymentMethodHandler
|
||||
{
|
||||
LightningPaymentData ParsePaymentDetails(JToken details);
|
||||
new LightningPaymentData ParsePaymentDetails(JToken details);
|
||||
}
|
||||
public class LightningLikePaymentHandler : IPaymentMethodHandler, ILightningPaymentHandler
|
||||
{
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
namespace BTCPayServer.Payments.Lightning
|
||||
{
|
||||
public class LightningPaymentMethodViewExtension : IPaymentMethodViewExtension
|
||||
{
|
||||
public LightningPaymentMethodViewExtension(PaymentMethodId paymentMethodId)
|
||||
{
|
||||
PaymentMethodId = paymentMethodId;
|
||||
}
|
||||
public PaymentMethodId PaymentMethodId { get; }
|
||||
|
||||
public void RegisterViews(PaymentMethodViewContext context)
|
||||
{
|
||||
context.RegisterCheckoutUI(new CheckoutUIPaymentMethodSettings()
|
||||
{
|
||||
ExtensionPartial = "Lightning/LightningLikeMethodCheckout",
|
||||
CheckoutBodyVueComponentName = "LightningLikeMethodCheckout",
|
||||
CheckoutHeaderVueComponentName = "LightningLikeMethodCheckoutHeader",
|
||||
NoScriptPartialName = "Lightning/LightningLikeMethodCheckoutNoScript"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,8 +42,6 @@ public partial class AltcoinsPlugin
|
||||
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId("XMR");
|
||||
services.AddBTCPayNetwork(network)
|
||||
.AddTransactionLinkProvider(pmi, new SimpleTransactionLinkProvider(blockExplorerLink));
|
||||
services.AddSingleton<IPaymentMethodViewExtension>(provider =>
|
||||
(IPaymentMethodViewExtension)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinPaymentMethodViewExtension), new object[] { pmi }));
|
||||
|
||||
|
||||
services.AddSingleton(provider =>
|
||||
@@ -69,12 +67,12 @@ public partial class AltcoinsPlugin
|
||||
(IPaymentMethodHandler)ActivatorUtilities.CreateInstance(provider, typeof(MoneroLikePaymentMethodHandler), new object[] { network }));
|
||||
services.AddSingleton<IPaymentLinkExtension>(provider =>
|
||||
(IPaymentLinkExtension)ActivatorUtilities.CreateInstance(provider, typeof(MoneroPaymentLinkExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentModelExtension>(provider =>
|
||||
(IPaymentModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(MoneroPaymentModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<ICheckoutModelExtension>(provider =>
|
||||
(ICheckoutModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(MoneroCheckoutModelExtension), new object[] { network, pmi }));
|
||||
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Monero/StoreNavMoneroExtension", "store-nav"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Monero/StoreWalletsNavMoneroExtension", "store-wallets-nav"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Monero/ViewMoneroLikePaymentData", "store-invoices-payments"));
|
||||
services.AddUIExtension("store-nav", "Monero/StoreNavMoneroExtension");
|
||||
services.AddUIExtension("store-wallets-nav", "Monero/StoreWalletsNavMoneroExtension");
|
||||
services.AddUIExtension("store-invoices-payments", "Monero/ViewMoneroLikePaymentData");
|
||||
services.AddSingleton<ISyncSummaryProvider, MoneroSyncSummaryProvider>();
|
||||
}
|
||||
private static MoneroLikeConfiguration ConfigureMoneroLikeConfiguration(IServiceProvider serviceProvider)
|
||||
|
||||
@@ -43,8 +43,6 @@ public partial class AltcoinsPlugin
|
||||
var pmi = PaymentTypes.CHAIN.GetPaymentMethodId("ZEC");
|
||||
services.AddBTCPayNetwork(network)
|
||||
.AddTransactionLinkProvider(pmi, new SimpleTransactionLinkProvider(blockExplorerLink));
|
||||
services.AddSingleton<IPaymentMethodViewExtension>(provider =>
|
||||
(IPaymentMethodViewExtension)ActivatorUtilities.CreateInstance(provider, typeof(BitcoinPaymentMethodViewExtension), new object[] { pmi }));
|
||||
|
||||
|
||||
services.AddSingleton(provider =>
|
||||
@@ -58,13 +56,13 @@ public partial class AltcoinsPlugin
|
||||
(IPaymentMethodHandler)ActivatorUtilities.CreateInstance(provider, typeof(ZcashLikePaymentMethodHandler), new object[] { network }));
|
||||
services.AddSingleton<IPaymentLinkExtension>(provider =>
|
||||
(IPaymentLinkExtension)ActivatorUtilities.CreateInstance(provider, typeof(ZcashPaymentLinkExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<IPaymentModelExtension>(provider =>
|
||||
(IPaymentModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(ZcashPaymentModelExtension), new object[] { network, pmi }));
|
||||
services.AddSingleton<ICheckoutModelExtension>(provider =>
|
||||
(ICheckoutModelExtension)ActivatorUtilities.CreateInstance(provider, typeof(ZcashCheckoutModelExtension), new object[] { network, pmi }));
|
||||
|
||||
services.AddSingleton<ZcashLikePaymentMethodHandler>();
|
||||
services.AddSingleton<IPaymentMethodHandler>(provider => provider.GetRequiredService<ZcashLikePaymentMethodHandler>());
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Zcash/StoreNavZcashExtension", "store-nav"));
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Zcash/ViewZcashLikePaymentData", "store-invoices-payments"));
|
||||
services.AddUIExtension("store-nav", "Zcash/StoreNavZcashExtension");
|
||||
services.AddUIExtension("store-invoices-payments", "Zcash/ViewZcashLikePaymentData");
|
||||
services.AddSingleton<ISyncSummaryProvider, ZcashSyncSummaryProvider>();
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace BTCPayServer.Plugins.Crowdfund
|
||||
|
||||
public override void Execute(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("Crowdfund/NavExtension", "header-nav"));
|
||||
services.AddUIExtension("header-nav", "Crowdfund/NavExtension");
|
||||
services.AddSingleton<CrowdfundAppType>();
|
||||
services.AddSingleton<AppBaseType, CrowdfundAppType>();
|
||||
|
||||
|
||||
@@ -15,12 +15,9 @@ namespace BTCPayServer.Plugins.NFC
|
||||
|
||||
public override void Execute(IServiceCollection applicationBuilder)
|
||||
{
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("NFC/CheckoutEnd",
|
||||
"checkout-end"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("NFC/LNURLNFCPostContent",
|
||||
"checkout-lightning-post-content"));
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("NFC/LNURLNFCPostContent",
|
||||
"checkout-bitcoin-post-content"));
|
||||
applicationBuilder.AddUIExtension("checkout-end", "NFC/CheckoutEnd");
|
||||
applicationBuilder.AddUIExtension("checkout-lightning-post-content", "NFC/LNURLNFCPostContent");
|
||||
applicationBuilder.AddUIExtension("checkout-bitcoin-post-content", "NFC/LNURLNFCPostContent");
|
||||
base.Execute(applicationBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace BTCPayServer.Plugins.PayButton
|
||||
|
||||
public override void Execute(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("PayButton/NavExtension", "header-nav"));
|
||||
services.AddUIExtension("header-nav", "PayButton/NavExtension");
|
||||
base.Execute(services);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace BTCPayServer.Plugins.PointOfSale
|
||||
|
||||
public override void Execute(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IUIExtension>(new UIExtension("PointOfSale/NavExtension", "header-nav"));
|
||||
services.AddUIExtension("header-nav", "PointOfSale/NavExtension");
|
||||
services.AddSingleton<AppBaseType, PointOfSaleAppType>();
|
||||
base.Execute(services);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace BTCPayServer.Plugins.Shopify
|
||||
{
|
||||
applicationBuilder.AddSingleton<ShopifyService>();
|
||||
applicationBuilder.AddSingleton<IHostedService, ShopifyService>(provider => provider.GetRequiredService<ShopifyService>());
|
||||
applicationBuilder.AddSingleton<IUIExtension>(new UIExtension("Shopify/NavExtension", "header-nav"));
|
||||
applicationBuilder.AddUIExtension("header-nav", "Shopify/NavExtension");
|
||||
base.Execute(applicationBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,19 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Bitcoin;
|
||||
using BTCPayServer.Payments.Lightning;
|
||||
using BTCPayServer.Services.Altcoins.Monero.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
|
||||
namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
{
|
||||
public class MoneroPaymentModelExtension : IPaymentModelExtension
|
||||
public class MoneroCheckoutModelExtension : ICheckoutModelExtension
|
||||
{
|
||||
private readonly BTCPayNetworkBase _network;
|
||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||
private readonly IPaymentLinkExtension paymentLinkExtension;
|
||||
|
||||
public MoneroPaymentModelExtension(
|
||||
public MoneroCheckoutModelExtension(
|
||||
PaymentMethodId paymentMethodId,
|
||||
IEnumerable<IPaymentLinkExtension> paymentLinkExtensions,
|
||||
BTCPayNetworkBase network,
|
||||
@@ -31,22 +32,23 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
public string Image => _network.CryptoImagePath;
|
||||
public string Badge => "";
|
||||
|
||||
public void ModifyPaymentModel(PaymentModelContext context)
|
||||
public void ModifyCheckoutModel(CheckoutModelContext context)
|
||||
{
|
||||
if (context is not { Handler: MoneroLikePaymentMethodHandler handler })
|
||||
return;
|
||||
context.Model.CheckoutBodyComponentName = BitcoinCheckoutModelExtension.CheckoutBodyComponentName;
|
||||
if (context.Model.Activated)
|
||||
{
|
||||
if (_handlers.TryGetValue(PaymentMethodId, out var handler))
|
||||
var details = context.InvoiceEntity.GetPayments(true)
|
||||
.Select(p => p.GetDetails<MoneroLikePaymentData>(handler))
|
||||
.Where(p => p is not null)
|
||||
.FirstOrDefault();
|
||||
if (details is not null)
|
||||
{
|
||||
var details = context.InvoiceEntity.GetPayments(true)
|
||||
.Select(p => p.GetDetails<MoneroLikePaymentData>(handler))
|
||||
.Where(p => p is not null)
|
||||
.FirstOrDefault();
|
||||
if (details is not null)
|
||||
{
|
||||
context.Model.ReceivedConfirmations = details.ConfirmationCount;
|
||||
context.Model.RequiredConfirmations = (int)MoneroListener.ConfirmationsRequired(details, context.InvoiceEntity.SpeedPolicy);
|
||||
}
|
||||
context.Model.ReceivedConfirmations = details.ConfirmationCount;
|
||||
context.Model.RequiredConfirmations = (int)MoneroListener.ConfirmationsRequired(details, context.InvoiceEntity.SpeedPolicy);
|
||||
}
|
||||
|
||||
context.Model.InvoiceBitcoinUrl = paymentLinkExtension.GetPaymentLink(context.Prompt, context.UrlHelper);
|
||||
context.Model.InvoiceBitcoinUrlQR = context.Model.InvoiceBitcoinUrl;
|
||||
}
|
||||
@@ -108,17 +108,6 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
return details.ToObject<MoneroLikeOnChainPaymentMethodDetails>(Serializer);
|
||||
}
|
||||
|
||||
public CheckoutUIPaymentMethodSettings GetCheckoutUISettings()
|
||||
{
|
||||
return new CheckoutUIPaymentMethodSettings
|
||||
{
|
||||
ExtensionPartial = "Bitcoin/BitcoinLikeMethodCheckout",
|
||||
CheckoutBodyVueComponentName = "BitcoinLikeMethodCheckout",
|
||||
CheckoutHeaderVueComponentName = "BitcoinLikeMethodCheckoutHeader",
|
||||
NoScriptPartialName = "Bitcoin/BitcoinLikeMethodCheckoutNoScript"
|
||||
};
|
||||
}
|
||||
|
||||
public MoneroLikePaymentData ParsePaymentDetails(JToken details)
|
||||
{
|
||||
return details.ToObject<MoneroLikePaymentData>(Serializer) ?? throw new FormatException($"Invalid {nameof(MoneroLikePaymentMethodHandler)}");
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.Payments.Bitcoin;
|
||||
using BTCPayServer.Services.Altcoins.Monero.Payments;
|
||||
using BTCPayServer.Services.Altcoins.Zcash.Services;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
|
||||
namespace BTCPayServer.Services.Altcoins.Zcash.Payments
|
||||
{
|
||||
public class ZcashPaymentModelExtension : IPaymentModelExtension
|
||||
public class ZcashCheckoutModelExtension : ICheckoutModelExtension
|
||||
{
|
||||
private readonly BTCPayNetworkBase _network;
|
||||
private readonly PaymentMethodHandlerDictionary _handlers;
|
||||
private readonly IPaymentLinkExtension paymentLinkExtension;
|
||||
|
||||
public ZcashPaymentModelExtension(
|
||||
public ZcashCheckoutModelExtension(
|
||||
PaymentMethodId paymentMethodId,
|
||||
IEnumerable<IPaymentLinkExtension> paymentLinkExtensions,
|
||||
BTCPayNetworkBase network,
|
||||
@@ -30,21 +32,21 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Payments
|
||||
public string Image => _network.CryptoImagePath;
|
||||
public string Badge => "";
|
||||
|
||||
public void ModifyPaymentModel(PaymentModelContext context)
|
||||
public void ModifyCheckoutModel(CheckoutModelContext context)
|
||||
{
|
||||
if (context.Model.Activated)
|
||||
if (context is not { Handler: ZcashLikePaymentMethodHandler handler })
|
||||
return;
|
||||
context.Model.CheckoutBodyComponentName = BitcoinCheckoutModelExtension.CheckoutBodyComponentName;
|
||||
if (context.Model.Activated)
|
||||
{
|
||||
if (_handlers.TryGetValue(PaymentMethodId, out var handler))
|
||||
var details = context.InvoiceEntity.GetPayments(true)
|
||||
.Select(p => p.GetDetails<ZcashLikePaymentData>(handler))
|
||||
.Where(p => p is not null)
|
||||
.FirstOrDefault();
|
||||
if (details is not null)
|
||||
{
|
||||
var details = context.InvoiceEntity.GetPayments(true)
|
||||
.Select(p => p.GetDetails<ZcashLikePaymentData>(handler))
|
||||
.Where(p => p is not null)
|
||||
.FirstOrDefault();
|
||||
if (details is not null)
|
||||
{
|
||||
context.Model.ReceivedConfirmations = details.ConfirmationCount;
|
||||
context.Model.RequiredConfirmations = (int)ZcashListener.ConfirmationsRequired(context.InvoiceEntity.SpeedPolicy);
|
||||
}
|
||||
context.Model.ReceivedConfirmations = details.ConfirmationCount;
|
||||
context.Model.RequiredConfirmations = (int)ZcashListener.ConfirmationsRequired(context.InvoiceEntity.SpeedPolicy);
|
||||
}
|
||||
context.Model.InvoiceBitcoinUrl = paymentLinkExtension.GetPaymentLink(context.Prompt, context.UrlHelper);
|
||||
context.Model.InvoiceBitcoinUrlQR = context.Model.InvoiceBitcoinUrl;
|
||||
@@ -102,17 +102,6 @@ namespace BTCPayServer.Services.Altcoins.Zcash.Payments
|
||||
public long AccountIndex { get; internal set; }
|
||||
}
|
||||
|
||||
public CheckoutUIPaymentMethodSettings GetCheckoutUISettings()
|
||||
{
|
||||
return new CheckoutUIPaymentMethodSettings
|
||||
{
|
||||
ExtensionPartial = "Bitcoin/BitcoinLikeMethodCheckout",
|
||||
CheckoutBodyVueComponentName = "BitcoinLikeMethodCheckout",
|
||||
CheckoutHeaderVueComponentName = "BitcoinLikeMethodCheckoutHeader",
|
||||
NoScriptPartialName = "Bitcoin/BitcoinLikeMethodCheckoutNoScript"
|
||||
};
|
||||
}
|
||||
|
||||
public ZcashLikePaymentData ParsePaymentDetails(JToken details)
|
||||
{
|
||||
return details.ToObject<ZcashLikePaymentData>(Serializer) ?? throw new FormatException($"Invalid {nameof(ZcashLikePaymentData)}");
|
||||
|
||||
@@ -6,9 +6,9 @@ namespace BTCPayServer.Services
|
||||
{
|
||||
public class PrettyNameProvider
|
||||
{
|
||||
private readonly Dictionary<PaymentMethodId, IPaymentModelExtension> _extensions;
|
||||
private readonly Dictionary<PaymentMethodId, ICheckoutModelExtension> _extensions;
|
||||
|
||||
public PrettyNameProvider(Dictionary<PaymentMethodId, IPaymentModelExtension> extensions)
|
||||
public PrettyNameProvider(Dictionary<PaymentMethodId, ICheckoutModelExtension> extensions)
|
||||
{
|
||||
_extensions = extensions;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
@using BTCPayServer.BIP78.Sender
|
||||
@using BTCPayServer.Components.TruncateCenter
|
||||
@using BTCPayServer.Abstractions.TagHelpers
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@using BTCPayServer.Payments.Bitcoin
|
||||
@model BTCPayServer.Models.InvoicingModels.CheckoutModel
|
||||
|
||||
<template id="bitcoin-method-checkout-template">
|
||||
<template id="@BitcoinCheckoutModelExtension.CheckoutBodyComponentName">
|
||||
@await Component.InvokeAsync("UiExtensionPoint", new {location = "checkout-bitcoin-pre-content", model = Model})
|
||||
<div class="payment-box">
|
||||
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.invoiceBitcoinUrl" data-clipboard-confirm-element="#Address_@Model.PaymentMethodId [data-clipboard]">
|
||||
@@ -12,9 +13,9 @@
|
||||
</div>
|
||||
<img class="qr-icon" :src="model.cryptoImage" :alt="model.paymentMethodName"/>
|
||||
</div>
|
||||
<div v-if="model.btcAddress" class="input-group mt-3">
|
||||
<div v-if="model.address" class="input-group mt-3">
|
||||
<div class="form-floating" id="Address_@Model.PaymentMethodId">
|
||||
<vc:truncate-center text="model.btcAddress" is-vue="true" padding="15" elastic="true" classes="form-control-plaintext" />
|
||||
<vc:truncate-center text="model.address" is-vue="true" padding="15" elastic="true" classes="form-control-plaintext" />
|
||||
<label v-t="{ path: 'address', args: { paymentMethod: model.paymentMethodName }}"></label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,9 +32,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
Vue.component('BitcoinLikeMethodCheckout', {
|
||||
Vue.component(@Safe.Json(BitcoinCheckoutModelExtension.CheckoutBodyComponentName), {
|
||||
props: ['model', 'nfcSupported', 'nfcScanning', 'nfcErrorMessage'],
|
||||
template: "#bitcoin-method-checkout-template",
|
||||
template: @Safe.Json("#" + BitcoinCheckoutModelExtension.CheckoutBodyComponentName),
|
||||
components: {
|
||||
qrcode: VueQrcode
|
||||
},
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
@model PaymentModel
|
||||
<div>
|
||||
<p>To complete payment, please send <b>@(Model.IsUnsetTopUp ? "any amount of" : Model.BtcDue) @Model.CryptoCode</b> to <b style="word-break: break-word;">@Model.BtcAddress</b></p>
|
||||
<p>Time remaining: @Model.TimeLeft</p>
|
||||
<p>
|
||||
<a href="@Model.InvoiceBitcoinUrl" style="word-break: break-word;" rel="noreferrer noopener">@Model.InvoiceBitcoinUrl</a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -7,10 +7,10 @@
|
||||
@inject DisplayFormatter DisplayFormatter
|
||||
@inject TransactionLinkProviders TransactionLinkProviders
|
||||
@inject PaymentMethodHandlerDictionary handlers
|
||||
@model IEnumerable<BTCPayServer.Services.Invoices.PaymentEntity>
|
||||
@model InvoiceDetailsModel
|
||||
@{
|
||||
PayjoinInformation payjoinInformation = null;
|
||||
var payments = Model
|
||||
var payments = Model.Payments
|
||||
.Select(payment =>
|
||||
{
|
||||
if (!handlers.TryGetValue(payment.PaymentMethodId, out var h) || h is not BitcoinLikePaymentHandler handler)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
@model BTCPayServer.Payments.LNURLPayPaymentMethodDetails
|
||||
|
||||
@if (!string.IsNullOrEmpty(Model.ProvidedComment))
|
||||
{
|
||||
<tr>
|
||||
<td colspan="100% bg-tile">
|
||||
LNURL Comment: @Model.ProvidedComment
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(Model.ConsumedLightningAddress))
|
||||
{
|
||||
<tr>
|
||||
<td colspan="100% bg-tile">
|
||||
Lightning address used: @Model.ConsumedLightningAddress
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
@model BTCPayServer.Models.InvoicingModels.PaymentModel
|
||||
@using BTCPayServer.Payments.Lightning
|
||||
@model BTCPayServer.Models.InvoicingModels.CheckoutModel
|
||||
|
||||
<template id="lightning-method-checkout-template">
|
||||
<template id="@LNCheckoutModelExtension.CheckoutBodyComponentName">
|
||||
<div class="payment-box">
|
||||
@await Component.InvokeAsync("UiExtensionPoint" , new { location="checkout-lightning-pre-content", model = Model})
|
||||
<div v-if="model.invoiceBitcoinUrlQR" class="qr-container" :data-qr-value="model.invoiceBitcoinUrlQR" :data-clipboard="model.invoiceBitcoinUrl" data-clipboard-confirm-element="#Lightning_@Model.PaymentMethodId [data-clipboard]">
|
||||
@@ -9,23 +10,23 @@
|
||||
</div>
|
||||
<img class="qr-icon" :src="model.cryptoImage" :alt="model.paymentMethodName"/>
|
||||
</div>
|
||||
<div v-if="model.btcAddress" class="input-group mt-3">
|
||||
<div v-if="model.address" class="input-group mt-3">
|
||||
<div class="form-floating" id="Lightning_@Model.PaymentMethodId">
|
||||
<vc:truncate-center text="model.btcAddress" is-vue="true" padding="15" elastic="true" classes="form-control-plaintext" />
|
||||
<vc:truncate-center text="model.address" is-vue="true" padding="15" elastic="true" classes="form-control-plaintext" />
|
||||
<label v-t="'lightning'"></label>
|
||||
</div>
|
||||
</div>
|
||||
<a v-if="model.invoiceBitcoinUrl && model.showPayInWalletButton" class="btn btn-primary rounded-pill w-100 mt-4" id="PayInWallet" target="_blank"
|
||||
:href="model.invoiceBitcoinUrl" v-t="'pay_in_wallet'"></a>
|
||||
<div v-if="!model.invoiceBitcoinUrl && !model.btcAddress" class="alert alert-danger">This payment method is not available when using an insecure connection. Please use HTTPS or Tor.</div>
|
||||
<div v-if="!model.invoiceBitcoinUrl && !model.address" class="alert alert-danger">This payment method is not available when using an insecure connection. Please use HTTPS or Tor.</div>
|
||||
@await Component.InvokeAsync("UiExtensionPoint", new {location = "checkout-lightning-post-content", model = Model})
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
Vue.component('LightningLikeMethodCheckout', {
|
||||
Vue.component(@Safe.Json(LNCheckoutModelExtension.CheckoutBodyComponentName), {
|
||||
props: ['model', 'nfcSupported', 'nfcScanning', 'nfcErrorMessage'],
|
||||
template: "#lightning-method-checkout-template",
|
||||
template: @Safe.Json("#" + LNCheckoutModelExtension.CheckoutBodyComponentName),
|
||||
components: {
|
||||
qrcode: VueQrcode
|
||||
},
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
@model PaymentModel
|
||||
<div>
|
||||
<p>To complete payment, please send <b>@Model.BtcDue @Model.CryptoCode</b> to <b style="word-break: break-word;">@Model.BtcAddress</b></p>
|
||||
<p>Time remaining: @Model.TimeLeft</p>
|
||||
<p>
|
||||
<a href="@Model.InvoiceBitcoinUrl" style="word-break: break-word;" rel="noreferrer noopener">@Model.InvoiceBitcoinUrl</a>
|
||||
</p>
|
||||
@if (!string.IsNullOrEmpty(Model.PeerInfo))
|
||||
{
|
||||
<p>Peer Info: <b>@Model.PeerInfo</b></p>
|
||||
}
|
||||
</div>
|
||||
@@ -7,16 +7,31 @@
|
||||
@inject DisplayFormatter DisplayFormatter
|
||||
@inject PaymentMethodHandlerDictionary handlers
|
||||
@inject PrettyNameProvider prettyName
|
||||
@model IEnumerable<BTCPayServer.Services.Invoices.PaymentEntity>
|
||||
@model InvoiceDetailsModel
|
||||
|
||||
@{
|
||||
string providedComment = null;
|
||||
string consumedLightningAddress = null;
|
||||
var payments = Model
|
||||
.Payments
|
||||
.Select(payment =>
|
||||
{
|
||||
|
||||
|
||||
if (handlers.TryGet(payment.PaymentMethodId) is not ILightningPaymentHandler handler)
|
||||
return null;
|
||||
var offChainPaymentData = handler.ParsePaymentDetails(payment.Details);
|
||||
|
||||
if (handler.ParsePaymentPromptDetails(Model.Entity.GetPaymentPrompt(payment.PaymentMethodId)?.Details) is LNURLPayPaymentMethodDetails lnurlPrompt)
|
||||
{
|
||||
if (lnurlPrompt.ConsumedLightningAddress is string consumed)
|
||||
{
|
||||
consumedLightningAddress = consumed;
|
||||
}
|
||||
if (lnurlPrompt.ProvidedComment is string comment)
|
||||
{
|
||||
providedComment = comment;
|
||||
}
|
||||
}
|
||||
return new OffChainPaymentViewModel
|
||||
{
|
||||
Type = prettyName.PrettyName(payment.PaymentMethodId),
|
||||
@@ -25,8 +40,8 @@
|
||||
Amount = DisplayFormatter.Currency(payment.Value, handler.Network.CryptoCode, divisibility: payment.Divisibility)
|
||||
};
|
||||
})
|
||||
.Where(model => model != null)
|
||||
.ToList();
|
||||
.Where(model => model != null)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
@if (payments.Any())
|
||||
@@ -37,7 +52,7 @@
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-75px">Type</th>
|
||||
<th class="w-175px">Type</th>
|
||||
<th class="w-175px">Destination</th>
|
||||
<th class="text-nowrap">Payment Proof</th>
|
||||
<th class="w-150px text-end">Paid</th>
|
||||
@@ -61,6 +76,19 @@
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@if (!string.IsNullOrEmpty(providedComment))
|
||||
{
|
||||
<div>
|
||||
<b>LNURL Comment</b>: @providedComment
|
||||
</div>
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(consumedLightningAddress))
|
||||
{
|
||||
<div>
|
||||
<b>Lightning address used</b>: @consumedLightningAddress
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</section>
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ Vue.component("lnurl-withdraw-checkout", {
|
||||
const {
|
||||
onChainWithLnInvoiceFallback: isUnified,
|
||||
paymentMethodId: activePaymentMethodId,
|
||||
availableCryptos: availablePaymentMethods,
|
||||
availablePaymentMethods: availablePaymentMethods,
|
||||
invoiceBitcoinUrl: paymentUrl
|
||||
} = this.model
|
||||
const lnurlwAvailable =
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@model PaymentModel
|
||||
@model CheckoutModel
|
||||
|
||||
<style>
|
||||
#checkout-cheating form + form { margin-top: var(--btcpay-space-l); }
|
||||
@@ -52,14 +52,14 @@
|
||||
paying: false,
|
||||
mining: false,
|
||||
expiring: false,
|
||||
amountRemaining: this.btcDue
|
||||
amountRemaining: this.due
|
||||
}
|
||||
},
|
||||
props: {
|
||||
invoiceId: String,
|
||||
paymentMethodId: String,
|
||||
cryptoCode: String,
|
||||
btcDue: Number,
|
||||
due: Number,
|
||||
isProcessing: Boolean,
|
||||
isSettled: Boolean
|
||||
},
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
@model PaymentModel
|
||||
@model CheckoutModel
|
||||
|
||||
<div id="testing">
|
||||
<hr class="my-3" />
|
||||
<p class="alert alert-danger" style="display: none; word-break: break-all;"></p>
|
||||
<p class="alert alert-success" style="display: none; word-break: break-all;"></p>
|
||||
<form id="test-payment" action="/i/@Model.InvoiceId/test-payment" method="post" class="cheat-mode form-inline my-2">
|
||||
<input name="CryptoCode" type="hidden" value="@Model.CryptoCode">
|
||||
<input name="CryptoCode" type="hidden" value="@Model.PaymentMethodCurrency">
|
||||
<div class="form-group mb-1">
|
||||
<label for="test-payment-amount" class="control-label">{{$t("Fake a @Model.CryptoCode payment for testing")}}</label>
|
||||
<label for="test-payment-amount" class="control-label">{{$t("Fake a @Model.PaymentMethodCurrency payment for testing")}}</label>
|
||||
<div class="input-group">
|
||||
<input id="test-payment-amount" name="Amount" type="number" step="0.00000001" min="0" class="form-control" placeholder="Amount" value="@Model.BtcDue" />
|
||||
<div id="test-payment-crypto-code" class="input-group-addon">@Model.CryptoCode</div>
|
||||
<input id="test-payment-amount" name="Amount" type="number" step="0.00000001" min="0" class="form-control" placeholder="Amount" value="@Model.Due" />
|
||||
<div id="test-payment-crypto-code" class="input-group-addon">@Model.PaymentMethodCurrency</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="FakePayment" class="btn btn-primary" type="submit">{{$t("Fake Payment")}}</button>
|
||||
|
||||
@@ -5,19 +5,19 @@
|
||||
@inject IEnumerable<IUIExtension> UiExtensions
|
||||
@inject PaymentMethodHandlerDictionary PaymentMethodHandlerDictionary
|
||||
@inject BTCPayServer.Security.ContentSecurityPolicies Csp
|
||||
@model PaymentModel
|
||||
@model CheckoutModel
|
||||
@{
|
||||
Layout = null;
|
||||
ViewData["Title"] = Model.HtmlTitle;
|
||||
ViewData["StoreBranding"] = Model.StoreBranding;
|
||||
Csp.UnsafeEval();
|
||||
var hasPaymentPlugins = UiExtensions.Any(extension => extension.Location == "checkout-payment-method");
|
||||
var displayedPaymentMethods = Model.AvailableCryptos.Where(c => c.Displayed).ToList();
|
||||
var displayedPaymentMethods = Model.AvailablePaymentMethods.Where(c => c.Displayed).ToList();
|
||||
}
|
||||
@functions {
|
||||
private string ToJsValue(object value)
|
||||
{
|
||||
return Safe.Json(value).ToString()?.Replace("\"", "'");
|
||||
return Safe.Json(value?.ToString()).ToString()?.Replace("\"", "'");
|
||||
}
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
@@ -60,7 +60,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<h2 id="AmountDue" v-text="`${srvModel.btcDue} ${srvModel.cryptoCode}`" :data-clipboard="asNumber(srvModel.btcDue)" data-clipboard-hover :data-amount-due="srvModel.btcDue">@Model.BtcDue @Model.CryptoCode</h2>
|
||||
<h2 id="AmountDue" v-text="`${srvModel.due} ${srvModel.paymentMethodCurrency}`" :data-clipboard="asNumber(srvModel.due)" data-clipboard-hover :data-amount-due="srvModel.due">@Model.Due @Model.PaymentMethodCurrency</h2>
|
||||
}
|
||||
</div>
|
||||
<div id="PaymentInfo" class="info mt-3 mb-2" v-collapsible="showInfo">
|
||||
@@ -73,7 +73,7 @@
|
||||
<vc:icon symbol="info" />
|
||||
<span v-t="'partial_payment_info'"></span>
|
||||
</div>
|
||||
<div v-if="showPaymentDueInfo" v-html="replaceNewlines($t('still_due', { amount: `${srvModel.btcDue} ${srvModel.cryptoCode}` }))"></div>
|
||||
<div v-if="showPaymentDueInfo" v-html="replaceNewlines($t('still_due', { amount: `${srvModel.due} ${srvModel.paymentMethodCurrency}` }))"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="DetailsToggle" class="d-flex align-items-center gap-1 btn btn-link payment-details-button mb-2" type="button" :aria-expanded="displayPaymentDetails ? 'true' : 'false'" v-on:click="displayPaymentDetails = !displayPaymentDetails">
|
||||
@@ -85,8 +85,8 @@
|
||||
:srv-model="srvModel"
|
||||
:is-active="isActive"
|
||||
:order-amount="orderAmount"
|
||||
:btc-paid="btcPaid"
|
||||
:btc-due="btcDue"
|
||||
:paid="paid"
|
||||
:due="due"
|
||||
:show-recommended-fee="showRecommendedFee"
|
||||
class="pb-4" />
|
||||
</div>
|
||||
@@ -108,7 +108,7 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<component v-if="paymentMethodComponent" :is="paymentMethodComponent"
|
||||
<component v-if="paymentMethodComponent" :is="paymentMethodComponent"
|
||||
:model="srvModel"
|
||||
:nfc-scanning="nfc.scanning"
|
||||
:nfc-supported="nfc.supported"
|
||||
@@ -127,7 +127,7 @@
|
||||
</span>
|
||||
<h4 v-t="'payment_received'" class="mb-4"></h4>
|
||||
<p class="text-center" v-t="'payment_received_body'"></p>
|
||||
<p class="text-center" v-if="srvModel.receivedConfirmations !== null && srvModel.requiredConfirmations" v-t="{ path: 'payment_received_confirmations', args: { cryptoCode: realCryptoCode, receivedConfirmations: srvModel.receivedConfirmations, requiredConfirmations: srvModel.requiredConfirmations } }"></p>
|
||||
<p class="text-center" v-if="srvModel.receivedConfirmations !== null && srvModel.requiredConfirmations" v-t="{ path: 'payment_received_confirmations', args: { cryptoCode: realPaymentMethodCurrency, receivedConfirmations: srvModel.receivedConfirmations, requiredConfirmations: srvModel.requiredConfirmations } }"></p>
|
||||
<div id="PaymentDetails" class="payment-details">
|
||||
<dl class="mb-0">
|
||||
<div>
|
||||
@@ -143,8 +143,8 @@
|
||||
:srv-model="srvModel"
|
||||
:is-active="isActive"
|
||||
:order-amount="orderAmount"
|
||||
:btc-paid="btcPaid"
|
||||
:btc-due="btcDue"
|
||||
:paid="paid"
|
||||
:due="due"
|
||||
:show-recommended-fee="showRecommendedFee"
|
||||
v-collapsible="displayPaymentDetails" />
|
||||
</div>
|
||||
@@ -180,8 +180,8 @@
|
||||
:srv-model="srvModel"
|
||||
:is-active="isActive"
|
||||
:order-amount="orderAmount"
|
||||
:btc-paid="btcPaid"
|
||||
:btc-due="btcDue"
|
||||
:paid="paid"
|
||||
:due="due"
|
||||
:show-recommended-fee="showRecommendedFee"
|
||||
class="mb-5" />
|
||||
</div>
|
||||
@@ -213,8 +213,8 @@
|
||||
:srv-model="srvModel"
|
||||
:is-active="isActive"
|
||||
:order-amount="orderAmount"
|
||||
:btc-paid="btcPaid"
|
||||
:btc-due="btcDue"
|
||||
:paid="paid"
|
||||
:due="due"
|
||||
:show-recommended-fee="showRecommendedFee"
|
||||
v-collapsible="displayPaymentDetails" />
|
||||
</div>
|
||||
@@ -234,7 +234,7 @@
|
||||
</main>
|
||||
@if (Env.CheatMode)
|
||||
{
|
||||
<checkout-cheating invoice-id="@Model.InvoiceId" :btc-due="btcDue" :is-settled="isSettled" :is-processing="isProcessing" :payment-method-id="pmId" :crypto-code="srvModel.cryptoCode"></checkout-cheating>
|
||||
<checkout-cheating invoice-id="@Model.InvoiceId" :due="due" :is-settled="isSettled" :is-processing="isProcessing" :payment-method-id="pmId" :crypto-code="srvModel.paymentMethodCurrency"></checkout-cheating>
|
||||
}
|
||||
<footer class="store-footer">
|
||||
<a class="store-powered-by" href="https://btcpayserver.org" target="_blank" rel="noreferrer noopener">
|
||||
@@ -257,33 +257,33 @@
|
||||
<dl>
|
||||
<div v-if="orderAmount > 0" id="PaymentDetails-TotalPrice" key="TotalPrice">
|
||||
<dt v-t="'total_price'"></dt>
|
||||
<dd :data-clipboard="asNumber(srvModel.orderAmount)" data-clipboard-hover="start">{{srvModel.orderAmount}} {{ srvModel.cryptoCode }}</dd>
|
||||
<dd :data-clipboard="asNumber(srvModel.orderAmount)" data-clipboard-hover="start">{{srvModel.orderAmount}} {{ srvModel.paymentMethodCurrency }}</dd>
|
||||
</div>
|
||||
<div v-if="orderAmount > 0 && srvModel.orderAmountFiat" id="PaymentDetails-TotalFiat" key="TotalFiat">
|
||||
<dt v-t="'total_fiat'"></dt>
|
||||
<dd :data-clipboard="asNumber(srvModel.orderAmountFiat)" data-clipboard-hover="start">{{srvModel.orderAmountFiat}}</dd>
|
||||
</div>
|
||||
<div v-if="srvModel.rate && srvModel.cryptoCode" id="PaymentDetails-ExchangeRate" key="ExchangeRate">
|
||||
<div v-if="srvModel.rate && srvModel.paymentMethodCurrency" id="PaymentDetails-ExchangeRate" key="ExchangeRate">
|
||||
<dt v-t="'exchange_rate'"></dt>
|
||||
<dd :data-clipboard="asNumber(srvModel.rate)" data-clipboard-hover="start">
|
||||
<template v-if="srvModel.cryptoCode === 'sats'">1 sat = {{ srvModel.rate }}</template>
|
||||
<template v-else>1 {{ srvModel.cryptoCode }} = {{ srvModel.rate }}</template>
|
||||
<template v-if="srvModel.paymentMethodCurrency === 'sats'">1 sat = {{ srvModel.rate }}</template>
|
||||
<template v-else>1 {{ srvModel.paymentMethodCurrency }} = {{ srvModel.rate }}</template>
|
||||
</dd>
|
||||
</div>
|
||||
<div v-if="srvModel.networkFee" id="PaymentDetails-NetworkCost" key="NetworkCost">
|
||||
<dt v-t="'network_cost'"></dt>
|
||||
<dd :data-clipboard="asNumber(srvModel.networkFee)" data-clipboard-hover="start">
|
||||
<div v-if="srvModel.txCountForFee > 0" v-t="{ path: 'tx_count', args: { count: srvModel.txCount } }"></div>
|
||||
<div v-text="`${srvModel.networkFee} ${srvModel.cryptoCode}`"></div>
|
||||
<div v-text="`${srvModel.networkFee} ${srvModel.paymentMethodCurrency}`"></div>
|
||||
</dd>
|
||||
</div>
|
||||
<div v-if="btcPaid > 0" id="PaymentDetails-AmountPaid" key="AmountPaid">
|
||||
<div v-if="paid > 0" id="PaymentDetails-AmountPaid" key="AmountPaid">
|
||||
<dt v-t="'amount_paid'"></dt>
|
||||
<dd :data-clipboard="asNumber(srvModel.btcPaid)" data-clipboard-hover="start" v-text="`${srvModel.btcPaid} ${srvModel.cryptoCode}`"></dd>
|
||||
<dd :data-clipboard="asNumber(srvModel.paid)" data-clipboard-hover="start" v-text="`${srvModel.paid} ${srvModel.paymentMethodCurrency}`"></dd>
|
||||
</div>
|
||||
<div v-if="btcDue > 0" id="PaymentDetails-AmountDue" key="AmountDue">
|
||||
<div v-if="due > 0" id="PaymentDetails-AmountDue" key="AmountDue">
|
||||
<dt v-t="'amount_due'"></dt>
|
||||
<dd :data-clipboard="asNumber(srvModel.btcDue)" data-clipboard-hover="start" v-text="`${srvModel.btcDue} ${srvModel.cryptoCode}`"></dd>
|
||||
<dd :data-clipboard="asNumber(srvModel.due)" data-clipboard-hover="start" v-text="`${srvModel.due} ${srvModel.paymentMethodCurrency}`"></dd>
|
||||
</div>
|
||||
<div v-if="showRecommendedFee" id="PaymentDetails-RecommendedFee" key="RecommendedFee">
|
||||
<dt v-t="'recommended_fee'"></dt>
|
||||
@@ -316,10 +316,6 @@
|
||||
@if (Env.CheatMode)
|
||||
{
|
||||
<partial name="Checkout-Cheating" model="@Model" />
|
||||
}
|
||||
@foreach (var extensionPartial in Model.ExtensionPartials)
|
||||
{
|
||||
<partial name="@extensionPartial" model="@Model" />
|
||||
}
|
||||
@await Component.InvokeAsync("UiExtensionPoint", new { location = "checkout-payment", model = Model })
|
||||
@await Component.InvokeAsync("UiExtensionPoint", new { location = "checkout-end", model = Model })
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@model PaymentModel
|
||||
@model CheckoutModel
|
||||
@{
|
||||
Layout = null;
|
||||
var displayedPaymentMethods = Model.AvailableCryptos.Where(a => a.Displayed).ToList();
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -17,36 +16,7 @@
|
||||
<h1>Pay with @Model.StoreName</h1>
|
||||
@if (Model.Status == "new")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Model.UISettings?.NoScriptPartialName))
|
||||
{
|
||||
<partial model="@Model" name="@Model.UISettings.NoScriptPartialName"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<h1 class="text-danger">This payment method requires javascript.</h1>
|
||||
}
|
||||
@if (displayedPaymentMethods.Count > 1)
|
||||
{
|
||||
<div>
|
||||
<hr />
|
||||
<h2>Pay with:</h2>
|
||||
<ul style="list-style-type: none;padding-left: 5px;">
|
||||
@foreach (var crypto in displayedPaymentMethods)
|
||||
{
|
||||
<li style="height: 32px; line-height: 32px;">
|
||||
<a asp-action="CheckoutNoScript" asp-route-invoiceId="@Model.InvoiceId" asp-route-paymentMethodId="@crypto.PaymentMethodId">
|
||||
<img alt="@crypto.PaymentMethodName" src="@crypto.CryptoImage" style="vertical-align:middle; height:24px; text-decoration:none; margin-top: -3px;" asp-append-version="true" />
|
||||
</a>
|
||||
<a asp-action="CheckoutNoScript" asp-route-invoiceId="@Model.InvoiceId" asp-route-paymentMethodId="@crypto.PaymentMethodId" style="padding-top: 2px;">
|
||||
@crypto.PaymentMethodName
|
||||
@(crypto.IsLightning ? Html.Raw("⚡") : null)
|
||||
(@crypto.CryptoCode)
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
<h1 class="text-danger">This payment method requires javascript.</h1>
|
||||
}
|
||||
else if (Model.Status == "paid" || Model.Status == "complete" || Model.Status == "confirmed")
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@using BTCPayServer.Payments
|
||||
@inject PaymentMethodViewProvider paymentMethodViewProvider
|
||||
@model (InvoiceDetailsModel Invoice, bool ShowAddress)
|
||||
@{
|
||||
var invoice = Model.Invoice;
|
||||
@@ -87,14 +86,10 @@
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
var vvm = paymentMethodViewProvider.TryGetViewViewModel(payment.PaymentMethodRaw, "AdditionalPaymentMethodDetails");;
|
||||
if (vvm != null)
|
||||
{
|
||||
<partial name="@((string)vvm.View)" model="@vvm.ViewModel" />
|
||||
}
|
||||
<vc:ui-extension-point location="invoice-payments-list" />
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<vc:ui-extension-point location="store-invoices-payments" model="@invoice.Payments" />
|
||||
<vc:ui-extension-point location="store-invoices-payments" model="@invoice" />
|
||||
|
||||
@@ -73,8 +73,8 @@ const PaymentDetails = {
|
||||
isActive: Boolean,
|
||||
showRecommendedFee: Boolean,
|
||||
orderAmount: Number,
|
||||
btcPaid: Number,
|
||||
btcDue: Number
|
||||
paid: Number,
|
||||
due: Number
|
||||
},
|
||||
methods: {
|
||||
asNumber
|
||||
@@ -129,7 +129,7 @@ function initApp() {
|
||||
return STATUS_PAYABLE.includes(this.srvModel.status);
|
||||
},
|
||||
isPaidPartial () {
|
||||
return this.btcPaid > 0 && this.btcDue > 0;
|
||||
return this.paid > 0 && this.due > 0;
|
||||
},
|
||||
showInfo () {
|
||||
return this.showTimer || this.showPaymentDueInfo;
|
||||
@@ -146,13 +146,13 @@ function initApp() {
|
||||
orderAmount () {
|
||||
return this.asNumber(this.srvModel.orderAmount);
|
||||
},
|
||||
btcDue () {
|
||||
return this.asNumber(this.srvModel.btcDue);
|
||||
due () {
|
||||
return this.asNumber(this.srvModel.due);
|
||||
},
|
||||
btcPaid () {
|
||||
return this.asNumber(this.srvModel.btcPaid);
|
||||
paid () {
|
||||
return this.asNumber(this.srvModel.paid);
|
||||
},
|
||||
pmId () {
|
||||
pmId() {
|
||||
return this.paymentMethodId || this.srvModel.paymentMethodId;
|
||||
},
|
||||
minutesLeft () {
|
||||
@@ -172,18 +172,18 @@ function initApp() {
|
||||
: null;
|
||||
},
|
||||
paymentMethodIds () {
|
||||
return this.srvModel.availableCryptos.map(function (c) { return c.paymentMethodId });
|
||||
return this.srvModel.availablePaymentMethods.map(function (c) { return c.paymentMethodId });
|
||||
},
|
||||
paymentMethodComponent () {
|
||||
paymentMethodComponent() {
|
||||
return this.isPluginPaymentMethod
|
||||
? `${this.pmId}Checkout`
|
||||
: this.srvModel.activated && this.srvModel.uiSettings.checkoutBodyVueComponentName;
|
||||
: this.srvModel.activated && this.srvModel.checkoutBodyComponentName;
|
||||
},
|
||||
isPluginPaymentMethod () {
|
||||
return !this.paymentMethodIds.includes(this.pmId);
|
||||
},
|
||||
realCryptoCode () {
|
||||
return this.srvModel.cryptoCode.toLowerCase() === 'sats' ? 'BTC' : this.srvModel.cryptoCode;
|
||||
realPaymentMethodCurrency () {
|
||||
return this.srvModel.paymentMethodCurrency.toLowerCase() === 'sats' ? 'BTC' : this.srvModel.paymentMethodCurrency;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
Reference in New Issue
Block a user