Compare commits

..

1 Commits

111 changed files with 984 additions and 4428 deletions

View File

@ -27,7 +27,7 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NBitcoin" Version="6.0.7" />
<PackageReference Include="NBitcoin" Version="6.0.4" />
<PackageReference Include="BTCPayServer.Lightning.Common" Version="1.2.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>

View File

@ -9,8 +9,6 @@ namespace BTCPayServer.Client.Models
{
public class CreateInvoiceRequest : InvoiceDataBase
{
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal? Amount { get; set; }
public string[] AdditionalSearchTerms { get; set; }
}
}

View File

@ -7,15 +7,10 @@ using Newtonsoft.Json.Linq;
namespace BTCPayServer.Client.Models
{
public enum InvoiceType
{
Standard,
TopUp
}
public class InvoiceDataBase
{
[JsonConverter(typeof(StringEnumConverter))]
public InvoiceType Type { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
public string Currency { get; set; }
public JObject Metadata { get; set; }
public CheckoutOptions Checkout { get; set; } = new CheckoutOptions();
@ -46,8 +41,6 @@ namespace BTCPayServer.Client.Models
{
public string Id { get; set; }
public string StoreId { get; set; }
[JsonConverter(typeof(NumericStringJsonConverter))]
public decimal Amount { get; set; }
public string CheckoutLink { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public InvoiceStatus Status { get; set; }

View File

@ -4,7 +4,7 @@
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="NBXplorer.Client" Version="4.0.3" />
<PackageReference Include="NBXplorer.Client" Version="4.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(Altcoins)' != 'true'">
<Compile Remove="Altcoins\**\*.cs"></Compile>

View File

@ -6,7 +6,7 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="NBitcoin" Version="6.0.7" />
<PackageReference Include="NBitcoin" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="DigitalRuby.ExchangeSharp" Version="0.6.3" />
</ItemGroup>

View File

@ -28,6 +28,7 @@ namespace BTCPayServer.Services.Rates
}
static readonly Dictionary<string, IFormatProvider> _CurrencyProviders = new Dictionary<string, IFormatProvider>();
public string FormatCurrency(string price, string currency)
{
return FormatCurrency(decimal.Parse(price, CultureInfo.InvariantCulture), currency);
@ -109,8 +110,9 @@ namespace BTCPayServer.Services.Rates
/// </summary>
/// <param name="value">The value</param>
/// <param name="currency">Currency code</param>
/// <param name="threeLetterSuffix">Add three letter suffix (like USD)</param>
/// <returns></returns>
public string DisplayFormatCurrency(decimal value, string currency)
public string DisplayFormatCurrency(decimal value, string currency, bool threeLetterSuffix = true)
{
var provider = GetNumberFormatInfo(currency, true);
var currencyData = GetCurrencyData(currency, true);

View File

@ -226,57 +226,6 @@ namespace BTCPayServer.Tests
}
}
[Fact]
[Trait("Selenium", "Selenium")]
public async Task CanUsePayjoinForTopUp()
{
using (var s = SeleniumTester.Create())
{
await s.StartAsync();
s.RegisterNewUser(true);
var receiver = s.CreateNewStore();
var receiverSeed = s.GenerateWallet("BTC", "", true, true, ScriptPubKeyType.Segwit);
var receiverWalletId = new WalletId(receiver.storeId, "BTC");
var sender = s.CreateNewStore();
var senderSeed = s.GenerateWallet("BTC", "", true, true, ScriptPubKeyType.Segwit);
var senderWalletId = new WalletId(sender.storeId, "BTC");
await s.Server.ExplorerNode.GenerateAsync(1);
await s.FundStoreWallet(senderWalletId);
await s.FundStoreWallet(receiverWalletId);
var invoiceId = s.CreateInvoice(receiver.storeName, null, "BTC");
s.GoToInvoiceCheckout(invoiceId);
var bip21 = s.Driver.FindElement(By.ClassName("payment__details__instruction__open-wallet__btn"))
.GetAttribute("href");
Assert.Contains($"{PayjoinClient.BIP21EndpointKey}=", bip21);
s.GoToWallet(senderWalletId, WalletsNavPages.Send);
s.Driver.FindElement(By.Id("bip21parse")).Click();
s.Driver.SwitchTo().Alert().SendKeys(bip21);
s.Driver.SwitchTo().Alert().Accept();
s.Driver.FindElement(By.Id("Outputs_0__Amount")).Clear();
s.Driver.FindElement(By.Id("Outputs_0__Amount")).SendKeys("0.023");
s.Driver.FindElement(By.Id("SignTransaction")).Click();
await s.Server.WaitForEvent<NewOnChainTransactionEvent>(() =>
{
s.Driver.FindElement(By.CssSelector("button[value=payjoin]")).Click();
return Task.CompletedTask;
});
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Success);
var invoiceRepository = s.Server.PayTester.GetService<InvoiceRepository>();
await TestUtils.EventuallyAsync(async () =>
{
var invoice = await invoiceRepository.GetInvoice(invoiceId);
Assert.Equal(InvoiceStatusLegacy.Paid, invoice.Status);
Assert.Equal(0.023m, invoice.Price);
});
}
}
[Fact]
[Trait("Selenium", "Selenium")]
public async Task CanUsePayjoinViaUI()

View File

@ -128,7 +128,6 @@ namespace BTCPayServer.Tests
public Mnemonic GenerateWallet(string cryptoCode = "BTC", string seed = "", bool importkeys = false, bool privkeys = false, ScriptPubKeyType format = ScriptPubKeyType.Segwit)
{
var isImport = !string.IsNullOrEmpty(seed);
Driver.FindElement(By.Id($"Modify{cryptoCode}")).Click();
// Replace previous wallet case
@ -138,7 +137,14 @@ namespace BTCPayServer.Tests
Driver.FindElement(By.Id("continue")).Click();
}
if (isImport)
if (string.IsNullOrEmpty(seed))
{
var option = privkeys ? "Hotwallet" : "Watchonly";
Logs.Tester.LogInformation($"Generating new seed ({option})");
Driver.FindElement(By.Id("GenerateWalletLink")).Click();
Driver.FindElement(By.Id($"Generate{option}Link")).Click();
}
else
{
Logs.Tester.LogInformation("Progressing with existing seed");
Driver.FindElement(By.Id("ImportWalletOptionsLink")).Click();
@ -146,13 +152,6 @@ namespace BTCPayServer.Tests
Driver.FindElement(By.Id("ExistingMnemonic")).SendKeys(seed);
Driver.SetCheckbox(By.Id("SavePrivateKeys"), privkeys);
}
else
{
var option = privkeys ? "Hotwallet" : "Watchonly";
Logs.Tester.LogInformation($"Generating new seed ({option})");
Driver.FindElement(By.Id("GenerateWalletLink")).Click();
Driver.FindElement(By.Id($"Generate{option}Link")).Click();
}
Driver.FindElement(By.Id("ScriptPubKeyType")).Click();
Driver.FindElement(By.CssSelector($"#ScriptPubKeyType option[value={format}]")).Click();
@ -161,25 +160,17 @@ namespace BTCPayServer.Tests
Driver.SetCheckbox(By.Id("ImportKeysToRPC"), importkeys);
Driver.FindElement(By.Id("Continue")).Click();
if (isImport)
// Seed backup page
FindAlertMessage();
if (string.IsNullOrEmpty(seed))
{
// Confirm addresses
Driver.FindElement(By.Id("Confirm")).Click();
seed = Driver.FindElements(By.Id("RecoveryPhrase")).First().GetAttribute("data-mnemonic");
}
else
{
// Seed backup
FindAlertMessage();
if (string.IsNullOrEmpty(seed))
{
seed = Driver.FindElements(By.Id("RecoveryPhrase")).First().GetAttribute("data-mnemonic");
}
// Confirm seed backup
Driver.FindElement(By.Id("confirm")).Click();
Driver.FindElement(By.Id("submit")).Click();
}
// Confirm seed backup
Driver.FindElement(By.Id("confirm")).Click();
Driver.FindElement(By.Id("submit")).Click();
WalletId = new WalletId(StoreId, cryptoCode);
return new Mnemonic(seed);
}
@ -331,12 +322,11 @@ namespace BTCPayServer.Tests
Driver.Navigate().GoToUrl(new Uri(Server.PayTester.ServerUri, "/login"));
}
public string CreateInvoice(string storeName, decimal? amount = 100, string currency = "USD", string refundEmail = "")
public string CreateInvoice(string storeName, decimal amount = 100, string currency = "USD", string refundEmail = "")
{
GoToInvoices();
Driver.FindElement(By.Id("CreateNewInvoice")).Click();
if (amount is decimal v)
Driver.FindElement(By.Id("Amount")).SendKeys(v.ToString(CultureInfo.InvariantCulture));
Driver.FindElement(By.Id("Amount")).SendKeys(amount.ToString(CultureInfo.InvariantCulture));
var currencyEl = Driver.FindElement(By.Id("Currency"));
currencyEl.Clear();
currencyEl.SendKeys(currency);

View File

@ -831,11 +831,6 @@ namespace BTCPayServer.Tests
s.Driver.FindElement(By.LinkText("Manage")).Click();
s.ClickOnAllSideMenus();
// Make sure wallet info is correct
s.Driver.FindElement(By.Id("WalletSettings")).Click();
Assert.Contains(mnemonic.DeriveExtKey().GetPublicKey().GetHDFingerPrint().ToString(), s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).GetAttribute("value"));
Assert.Contains("m/84'/1'/0'", s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).GetAttribute("value"));
// Make sure we can rescan, because we are admin!
s.Driver.FindElement(By.Id("WalletRescan")).Click();
@ -913,23 +908,6 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = TestTimeout)]
public async Task CanImportWallet()
{
using (var s = SeleniumTester.Create())
{
await s.StartAsync();
s.RegisterNewUser(true);
var (_, storeId) = s.CreateNewStore();
var mnemonic = s.GenerateWallet("BTC", "click chunk owner kingdom faint steak safe evidence bicycle repeat bulb wheel");
// Make sure wallet info is correct
s.GoToWallet(new WalletId(storeId, "BTC"), WalletsNavPages.Settings);
Assert.Contains(mnemonic.DeriveExtKey().GetPublicKey().GetHDFingerPrint().ToString(), s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).GetAttribute("value"));
Assert.Contains( "m/84'/1'/0'", s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).GetAttribute("value"));
}
}
[Fact]
[Trait("Selenium", "Selenium")]
public async Task CanUsePullPaymentsViaUI()
@ -1081,7 +1059,7 @@ namespace BTCPayServer.Tests
Assert.Contains(PayoutState.AwaitingPayment.GetStateString(), s.Driver.PageSource);
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-selectAllCheckbox")).Click();
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-actions")).Click();
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-mark-paid")).Click();
s.Driver.FindElement(By.Id($"{PayoutState.AwaitingPayment}-confirm-payment")).Click();
s.FindAlertMessage();
s.Driver.FindElement(By.Id("InProgress-view")).Click();

View File

@ -13,7 +13,6 @@ using BTCPayServer.Tests.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Xunit;
using Xunit.Abstractions;
@ -186,23 +185,22 @@ namespace BTCPayServer.Tests
fileList.Add(TestUtils.GetFormFile("uploadtestfile1.txt", fileContent));
var uploadFormFileResult = Assert.IsType<RedirectToActionResult>(await controller.CreateFiles(fileList));
Assert.True(uploadFormFileResult.RouteValues.ContainsKey("fileIds"));
string[] uploadFileList = (string[])uploadFormFileResult.RouteValues["fileIds"];
var fileId = uploadFileList[0];
Assert.True(uploadFormFileResult.RouteValues.ContainsKey("fileId"));
var fileId = uploadFormFileResult.RouteValues["fileId"].ToString();
Assert.Equal("Files", uploadFormFileResult.ActionName);
//check if file was uploaded and saved in db
var viewFilesViewModel =
Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(new string[] { fileId })).Model);
Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(fileId)).Model);
Assert.NotEmpty(viewFilesViewModel.Files);
Assert.True(viewFilesViewModel.DirectUrlByFiles.ContainsKey(fileId));
Assert.NotEmpty(viewFilesViewModel.DirectUrlByFiles[fileId]);
Assert.Equal(fileId, viewFilesViewModel.SelectedFileId);
Assert.NotEmpty(viewFilesViewModel.DirectFileUrl);
//verify file is available and the same
var net = new System.Net.WebClient();
var data = await net.DownloadStringTaskAsync(new Uri(viewFilesViewModel.DirectUrlByFiles[fileId]));
var data = await net.DownloadStringTaskAsync(new Uri(viewFilesViewModel.DirectFileUrl));
Assert.Equal(fileContent, data);
//create a temporary link to file
@ -234,8 +232,10 @@ namespace BTCPayServer.Tests
//attempt to fetch deleted file
viewFilesViewModel =
Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(new string[] { fileId })).Model);
Assert.Null(viewFilesViewModel.DirectUrlByFiles);
Assert.IsType<ViewFilesViewModel>(Assert.IsType<ViewResult>(await controller.Files(fileId)).Model);
Assert.Null(viewFilesViewModel.DirectFileUrl);
Assert.Null(viewFilesViewModel.SelectedFileId);
}

View File

@ -935,8 +935,7 @@ namespace BTCPayServer.Tests
{
(0.0005m, "$0.0005 (USD)", "USD"), (0.001m, "$0.001 (USD)", "USD"), (0.01m, "$0.01 (USD)", "USD"),
(0.1m, "$0.10 (USD)", "USD"), (0.1m, "0,10 € (EUR)", "EUR"), (1000m, "¥1,000 (JPY)", "JPY"),
(1000.0001m, "₹ 1,000.00 (INR)", "INR"),
(0.0m, "$0.00 (USD)", "USD")
(1000.0001m, "₹ 1,000.00 (INR)", "INR")
})
{
var actual = CurrencyNameTable.Instance.DisplayFormatCurrency(test.Item1, test.Item3);
@ -2100,90 +2099,6 @@ namespace BTCPayServer.Tests
}
}
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanCreateTopupInvoices()
{
using (var tester = ServerTester.Create())
{
await tester.StartAsync();
var user = tester.NewAccount();
user.GrantAccess();
user.RegisterDerivationScheme("BTC");
var rng = new Random();
var seed = rng.Next();
rng = new Random(seed);
Logs.Tester.LogInformation("Seed: " + seed);
foreach (var networkFeeMode in Enum.GetValues(typeof(NetworkFeeMode)).Cast<NetworkFeeMode>())
{
await user.SetNetworkFeeMode(networkFeeMode);
await AssertTopUpBtcPrice(tester, user, Money.Coins(1.0m), 5000.0m, networkFeeMode);
await AssertTopUpBtcPrice(tester, user, Money.Coins(1.23456789m), 5000.0m * 1.23456789m, networkFeeMode);
// Check if there is no strange roundup issues
var v = (decimal)(rng.NextDouble() + 1.0);
v = Money.Coins(v).ToDecimal(MoneyUnit.BTC);
await AssertTopUpBtcPrice(tester, user, Money.Coins(v), 5000.0m * v, networkFeeMode);
}
}
}
private static async Task AssertTopUpBtcPrice(ServerTester tester, TestAccount user, Money btcSent, decimal expectedPriceWithoutNetworkFee, NetworkFeeMode networkFeeMode)
{
var cashCow = tester.ExplorerNode;
// First we try payment with a merchant having only BTC
var client = await user.CreateClient();
var invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest()
{
Amount = null,
Currency = "USD"
});
Assert.Equal(0m, invoice.Amount);
Assert.Equal(InvoiceType.TopUp, invoice.Type);
var btcmethod = (await client.GetInvoicePaymentMethods(user.StoreId, invoice.Id))[0];
var paid = btcSent;
var invoiceAddress = BitcoinAddress.Create(btcmethod.Destination, cashCow.Network);
var btc = new PaymentMethodId("BTC", PaymentTypes.BTCLike);
var networkFee = (await tester.PayTester.InvoiceRepository.GetInvoice(invoice.Id))
.GetPaymentMethods()[btc]
.GetPaymentMethodDetails()
.AssertType<BitcoinLikeOnChainPaymentMethod>()
.GetNextNetworkFee();
if (networkFeeMode != NetworkFeeMode.Always)
{
networkFee = 0.0m;
}
cashCow.SendToAddress(invoiceAddress, paid);
await TestUtils.EventuallyAsync(async () =>
{
try
{
var bitpayinvoice = await user.BitPay.GetInvoiceAsync(invoice.Id);
Assert.NotEqual(0.0m, bitpayinvoice.Price);
var due = Money.Parse(bitpayinvoice.CryptoInfo[0].CryptoPaid);
Assert.Equal(paid, due);
Assert.Equal(expectedPriceWithoutNetworkFee - networkFee * bitpayinvoice.Rate, bitpayinvoice.Price);
Assert.Equal(Money.Zero, bitpayinvoice.BtcDue);
Assert.Equal("paid", bitpayinvoice.Status);
Assert.Equal("False", bitpayinvoice.ExceptionStatus.ToString());
// Check if we index by price correctly once we know it
var invoices = await client.GetInvoices(user.StoreId, textSearch: $"{bitpayinvoice.Price.ToString(CultureInfo.InvariantCulture)}");
Assert.Contains(invoices, inv => inv.Id == bitpayinvoice.Id);
}
catch (JsonSerializationException)
{
Assert.False(true, "The bitpay's amount is not set");
}
});
}
[Fact(Timeout = LongRunningTestTimeout)]
[Trait("Integration", "Integration")]
public async Task CanModifyRates()
@ -2888,22 +2803,6 @@ namespace BTCPayServer.Tests
var invoice = user.BitPay.CreateInvoice(
new Invoice() { Price = -0.1m, Currency = "BTC", FullNotifications = true }, Facade.Merchant);
Assert.Equal(0.0m, invoice.Price);
// Should round down to 50.51, taxIncluded should be also clipped to this value because taxIncluded can't be higher than the price.
var invoice5 = user.BitPay.CreateInvoice(
new Invoice() { Price = 50.513m, Currency = "USD", FullNotifications = true, TaxIncluded = 50.516m }, Facade.Merchant);
Assert.Equal(50.51m, invoice5.Price);
Assert.Equal(50.51m, invoice5.TaxIncluded);
var greenfield = await user.CreateClient();
var invoice5g = await greenfield.CreateInvoice(user.StoreId, new CreateInvoiceRequest()
{
Amount = 50.513m,
Currency = "USD",
Metadata = new JObject() { new JProperty("taxIncluded", 50.516m) }
});
Assert.Equal(50.51m, invoice5g.Amount);
Assert.Equal(50.51m, (decimal)invoice5g.Metadata["taxIncluded"]);
}
}

View File

@ -69,7 +69,7 @@ services:
- "sshd_datadir:/root/.ssh"
devlnd:
image: btcpayserver/bitcoin:0.21.1
image: btcpayserver/bitcoin:0.21.0
environment:
BITCOIN_NETWORK: regtest
BITCOIN_WALLETDIR: "/data/wallets"
@ -84,7 +84,7 @@ services:
- customer_lnd
- merchant_lnd
nbxplorer:
image: nicolasdorier/nbxplorer:2.1.56
image: nicolasdorier/nbxplorer:2.1.53
restart: unless-stopped
ports:
- "32838:32838"
@ -118,7 +118,7 @@ services:
bitcoind:
restart: unless-stopped
image: btcpayserver/bitcoin:0.21.1
image: btcpayserver/bitcoin:0.21.0
environment:
BITCOIN_NETWORK: regtest
BITCOIN_WALLETDIR: "/data/wallets"
@ -146,7 +146,7 @@ services:
- "bitcoin_datadir:/data"
customer_lightningd:
image: btcpayserver/lightning:v0.10.1-dev
image: btcpayserver/lightning:v0.9.3-1-dev
stop_signal: SIGKILL
restart: unless-stopped
environment:
@ -195,7 +195,7 @@ services:
- merchant_lightningd
merchant_lightningd:
image: btcpayserver/lightning:v0.10.1-dev
image: btcpayserver/lightning:v0.9.3-1-dev
stop_signal: SIGKILL
environment:
EXPOSE_TCP: "true"
@ -227,7 +227,7 @@ services:
- "5432"
merchant_lnd:
image: btcpayserver/lnd:v0.13.1-beta-withloop
image: btcpayserver/lnd:v0.12.1-beta
restart: unless-stopped
environment:
LND_CHAIN: "btc"
@ -261,7 +261,7 @@ services:
- bitcoind
customer_lnd:
image: btcpayserver/lnd:v0.13.1-beta-withloop
image: btcpayserver/lnd:v0.12.1-beta
restart: unless-stopped
environment:
LND_CHAIN: "btc"

View File

@ -66,7 +66,7 @@ services:
- "sshd_datadir:/root/.ssh"
devlnd:
image: btcpayserver/bitcoin:0.21.1
image: btcpayserver/bitcoin:0.21.0
environment:
BITCOIN_NETWORK: regtest
BITCOIN_WALLETDIR: "/data/wallets"
@ -81,7 +81,7 @@ services:
- customer_lnd
- merchant_lnd
nbxplorer:
image: nicolasdorier/nbxplorer:2.1.56
image: nicolasdorier/nbxplorer:2.1.53
restart: unless-stopped
ports:
- "32838:32838"
@ -105,7 +105,7 @@ services:
bitcoind:
restart: unless-stopped
image: btcpayserver/bitcoin:0.21.1
image: btcpayserver/bitcoin:0.21.0
environment:
BITCOIN_NETWORK: regtest
BITCOIN_WALLETDIR: "/data/wallets"
@ -133,7 +133,7 @@ services:
- "bitcoin_datadir:/data"
customer_lightningd:
image: btcpayserver/lightning:v0.10.1-dev
image: btcpayserver/lightning:v0.9.3-1-dev
stop_signal: SIGKILL
restart: unless-stopped
environment:
@ -182,7 +182,7 @@ services:
- merchant_lightningd
merchant_lightningd:
image: btcpayserver/lightning:v0.10.1-dev
image: btcpayserver/lightning:v0.9.3-1-dev
stop_signal: SIGKILL
environment:
EXPOSE_TCP: "true"
@ -215,7 +215,7 @@ services:
- "5432"
merchant_lnd:
image: btcpayserver/lnd:v0.13.1-beta-withloop
image: btcpayserver/lnd:v0.12.1-beta
restart: unless-stopped
environment:
LND_CHAIN: "btc"
@ -249,7 +249,7 @@ services:
- bitcoind
customer_lnd:
image: btcpayserver/lnd:v0.13.1-beta-withloop
image: btcpayserver/lnd:v0.12.1-beta
restart: unless-stopped
environment:
LND_CHAIN: "btc"

View File

@ -46,7 +46,7 @@
<ItemGroup>
<PackageReference Include="BIP78.Sender" Version="0.2.0" />
<PackageReference Include="BTCPayServer.Hwi" Version="2.0.1" />
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.2.10" />
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.2.9" />
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" />
<PackageReference Include="BundlerMinifier.Core" Version="3.2.435" />
<PackageReference Include="BundlerMinifier.TagHelpers" Version="3.2.435" />

View File

@ -3,7 +3,6 @@
@inject ISettingsRepository SettingsRepository
@using BTCPayServer.HostedServices
@using BTCPayServer.Views.Notifications
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Client
@using BTCPayServer.Services

View File

@ -393,7 +393,6 @@ namespace BTCPayServer.Controllers.GreenField
MonitoringExpiration = entity.MonitoringExpiration,
CreatedTime = entity.InvoiceTime,
Amount = entity.Price,
Type = entity.Type,
Id = entity.Id,
CheckoutLink = _linkGenerator.CheckoutLink(entity.Id, Request.Scheme, Request.Host, Request.PathBase),
Status = entity.Status.ToModernStatus(),

View File

@ -247,7 +247,8 @@ namespace BTCPayServer.Controllers
cdCurrency.Divisibility);
model.CryptoAmountThen = Math.Round(paidCurrency / paymentMethod.Rate, paymentMethodDivisibility);
model.RateThenText =
_CurrencyNameTable.DisplayFormatCurrency(model.CryptoAmountThen, paymentMethodId.CryptoCode);
_CurrencyNameTable.DisplayFormatCurrency(model.CryptoAmountThen, paymentMethodId.CryptoCode,
true);
rules = store.GetStoreBlob().GetRateRules(_NetworkProvider);
rateResult = await _RateProvider.FetchRate(
new Rating.CurrencyPair(paymentMethodId.CryptoCode, invoice.Currency), rules,
@ -262,9 +263,10 @@ namespace BTCPayServer.Controllers
model.CryptoAmountNow = Math.Round(paidCurrency / rateResult.BidAsk.Bid, paymentMethodDivisibility);
model.CurrentRateText =
_CurrencyNameTable.DisplayFormatCurrency(model.CryptoAmountNow, paymentMethodId.CryptoCode);
_CurrencyNameTable.DisplayFormatCurrency(model.CryptoAmountNow, paymentMethodId.CryptoCode,
true);
model.FiatAmount = paidCurrency;
model.FiatText = _CurrencyNameTable.DisplayFormatCurrency(model.FiatAmount, invoice.Currency);
model.FiatText = _CurrencyNameTable.DisplayFormatCurrency(model.FiatAmount, invoice.Currency, true);
return View(model);
case RefundSteps.SelectRate:
createPullPayment = new HostedServices.CreatePullPayment();
@ -339,7 +341,7 @@ namespace BTCPayServer.Controllers
var ppId = await _paymentHostedService.CreatePullPayment(createPullPayment);
this.TempData.SetStatusMessageModel(new StatusMessageModel()
{
Html = "Refund successfully created!<br />Share the link to this page with a customer.<br />The customer needs to enter their address and claim the refund.<br />Once a customer claims the refund, you will get a notification and would need to approve and initiate it from your Wallet > Manage > Payouts.",
Html = "Share this page with a customer so they can claim a refund <br />Once claimed you need to initiate a refund from Wallet > Payouts",
Severity = StatusMessageModel.StatusSeverity.Success
});
(await ctx.Invoices.FindAsync(invoice.Id)).CurrentRefundId = ppId;
@ -543,7 +545,7 @@ namespace BTCPayServer.Controllers
}
}
lang ??= storeBlob.DefaultLang;
var model = new PaymentModel()
{
Activated = paymentMethodDetails.Activated,
@ -560,7 +562,6 @@ namespace BTCPayServer.Controllers
BtcDue = accounting.Due.ShowMoney(divisibility),
InvoiceCurrency = invoice.Currency,
OrderAmount = (accounting.TotalDue - accounting.NetworkFee).ShowMoney(divisibility),
IsUnsetTopUp = invoice.IsUnsetTopUp(),
OrderAmountFiat = OrderAmountFromInvoice(network.CryptoCode, invoice),
CustomerEmail = invoice.RefundMail,
RequiresRefundEmail = storeBlob.RequiresRefundEmail,
@ -845,12 +846,17 @@ namespace BTCPayServer.Controllers
ModelState.AddModelError(nameof(model.StoreId), "You need to configure the derivation scheme in order to create an invoice");
return View(model);
}
if (model.Amount is null)
{
ModelState.AddModelError(nameof(model.Amount), "Thhe invoice amount can't be empty");
return View(model);
}
try
{
var result = await CreateInvoiceCore(new BitpayCreateInvoiceRequest()
{
Price = model.Amount,
Price = model.Amount.Value,
Currency = model.Currency,
PosData = model.PosData,
OrderId = model.OrderId,

View File

@ -112,23 +112,24 @@ namespace BTCPayServer.Controllers
FillBuyerInfo(invoice, entity);
var taxIncluded = invoice.TaxIncluded.HasValue ? invoice.TaxIncluded.Value : 0m;
var price = invoice.Price;
var currencyInfo = _CurrencyNameTable.GetNumberFormatInfo(invoice.Currency, false);
if (currencyInfo != null)
{
int divisibility = currencyInfo.CurrencyDecimalDigits;
invoice.Price = invoice.Price.RoundToSignificant(ref divisibility);
divisibility = currencyInfo.CurrencyDecimalDigits;
invoice.TaxIncluded = taxIncluded.RoundToSignificant(ref divisibility);
}
invoice.Price = Math.Max(0.0m, invoice.Price);
invoice.TaxIncluded = Math.Max(0.0m, taxIncluded);
invoice.TaxIncluded = Math.Min(taxIncluded, invoice.Price);
entity.Metadata.ItemCode = invoice.ItemCode;
entity.Metadata.ItemDesc = invoice.ItemDesc;
entity.Metadata.Physical = invoice.Physical;
entity.Metadata.TaxIncluded = invoice.TaxIncluded;
entity.Currency = invoice.Currency;
if (price is decimal vv)
{
entity.Price = vv;
entity.Type = InvoiceType.Standard;
}
else
{
entity.Price = 0m;
entity.Type = InvoiceType.TopUp;
}
entity.Price = invoice.Price;
entity.RedirectURLTemplate = invoice.RedirectURL ?? store.StoreWebsite;
entity.RedirectAutomatically =
@ -170,16 +171,7 @@ namespace BTCPayServer.Controllers
invoice.Checkout ??= new CreateInvoiceRequest.CheckoutOptions();
invoice.Currency = invoice.Currency?.Trim().ToUpperInvariant() ?? "USD";
entity.Currency = invoice.Currency;
if (invoice.Amount is decimal v)
{
entity.Price = v;
entity.Type = InvoiceType.Standard;
}
else
{
entity.Price = 0.0m;
entity.Type = InvoiceType.TopUp;
}
entity.Price = invoice.Amount;
entity.SpeedPolicy = invoice.Checkout.SpeedPolicy ?? store.SpeedPolicy;
entity.DefaultLanguage = invoice.Checkout.DefaultLanguage;
entity.RedirectAutomatically = invoice.Checkout.RedirectAutomatically ?? storeBlob.RedirectAutomatically;
@ -203,23 +195,6 @@ namespace BTCPayServer.Controllers
InvoiceLogs logs = new InvoiceLogs();
logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info);
entity.Price = Math.Max(0.0m, entity.Price);
var currencyInfo = _CurrencyNameTable.GetNumberFormatInfo(entity.Currency, false);
if (currencyInfo != null)
{
entity.Price = entity.Price.RoundToSignificant(currencyInfo.CurrencyDecimalDigits);
}
if (entity.Metadata.TaxIncluded is decimal taxIncluded)
{
if (currencyInfo != null)
{
taxIncluded = taxIncluded.RoundToSignificant(currencyInfo.CurrencyDecimalDigits);
}
taxIncluded = Math.Max(0.0m, taxIncluded);
taxIncluded = Math.Min(taxIncluded, entity.Price);
entity.Metadata.TaxIncluded = taxIncluded;
}
var getAppsTaggingStore = _InvoiceRepository.GetAppsTaggingStore(store.Id);
var storeBlob = store.GetStoreBlob();

View File

@ -477,7 +477,7 @@ namespace BTCPayServer.Controllers
{$"{BTCPayServer.Client.Policies.CanModifyStoreWebhooks}:", ("Modify selected stores' webhooks", "The app will modify the webhooks of the selected stores.")},
{BTCPayServer.Client.Policies.CanViewStoreSettings, ("View your stores", "The app will be able to view stores settings.")},
{$"{BTCPayServer.Client.Policies.CanViewStoreSettings}:", ("View your stores", "The app will be able to view the selected stores' settings.")},
{BTCPayServer.Client.Policies.CanModifyServerSettings, ("Manage your server", "The app will have total control on the server settings of your server.")},
{BTCPayServer.Client.Policies.CanModifyServerSettings, ("Manage your server", "The app will have total control on the server settings of your server")},
{BTCPayServer.Client.Policies.CanViewProfile, ("View your profile", "The app will be able to view your user profile.")},
{BTCPayServer.Client.Policies.CanModifyProfile, ("Manage your profile", "The app will be able to view and modify your user profile.")},
{BTCPayServer.Client.Policies.CanManageNotificationsForUser, ("Manage your notifications", "The app will be able to view and modify your user notifications.")},

View File

@ -48,7 +48,7 @@ namespace BTCPayServer.Controllers
ModelState.AddModelError("Store", "Store has not enabled Pay Button");
}
if (model == null || (model.Price is decimal v ? v <= 0 : false))
if (model == null || model.Price <= 0)
ModelState.AddModelError("Price", "Price must be greater than 0");
if (!ModelState.IsValid)

View File

@ -22,51 +22,24 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Controllers
{
public partial class ServerController
{
[HttpGet("server/files")]
public async Task<IActionResult> Files([FromQuery] string[] fileIds = null)
[HttpGet("server/files/{fileId?}")]
public async Task<IActionResult> Files(string fileId = null)
{
var fileUrl = string.IsNullOrEmpty(fileId) ? null : await _FileService.GetFileUrl(Request.GetAbsoluteRootUri(), fileId);
var model = new ViewFilesViewModel()
{
Files = await _StoredFileRepository.GetFiles(),
DirectUrlByFiles = null,
Files = await _StoredFileRepository.GetFiles(),
SelectedFileId = string.IsNullOrEmpty(fileUrl) ? null : fileId,
DirectFileUrl = fileUrl,
StorageConfigured = (await _SettingsRepository.GetSettingAsync<StorageSettings>()) != null
};
if (fileIds != null && fileIds.Length > 0)
{
bool allFilesExist = true;
Dictionary<string, string> directUrlByFiles = new Dictionary<string, string>();
foreach (string filename in fileIds)
{
string fileUrl = await _FileService.GetFileUrl(Request.GetAbsoluteRootUri(), filename);
if (fileUrl == null)
{
allFilesExist = false;
break;
}
directUrlByFiles.Add(filename, fileUrl);
}
if (!allFilesExist)
{
this.TempData.SetStatusMessageModel(new StatusMessageModel()
{
Message = "Some of the files were not found",
Severity = StatusMessageModel.StatusSeverity.Warning,
});
}
else
{
model.DirectUrlByFiles = directUrlByFiles;
}
}
return View(model);
}
@ -78,7 +51,7 @@ namespace BTCPayServer.Controllers
await _FileService.RemoveFile(fileId, null);
return RedirectToAction(nameof(Files), new
{
fileIds = Array.Empty<string>(),
fileId = "",
statusMessage = "File removed"
});
}
@ -154,7 +127,7 @@ namespace BTCPayServer.Controllers
});
return RedirectToAction(nameof(Files), new
{
fileIds = new string[] { fileId }
fileId
});
}
@ -217,10 +190,18 @@ namespace BTCPayServer.Controllers
Severity = statusMessageSeverity
});
return RedirectToAction(nameof(Files), new
{
fileIds = fileIds.ToArray(),
});
if (fileIds.Count == 1)
{
return RedirectToAction(nameof(Files), new
{
statusMessage = "File added!",
fileId = fileIds[0]
});
}
else
{
return RedirectToAction(nameof(Files));
}
}
else
{

View File

@ -455,7 +455,7 @@ namespace BTCPayServer.Controllers
[Route("server/services/{serviceName}/{cryptoCode?}")]
public async Task<IActionResult> Service(string serviceName, string cryptoCode, bool showQR = false, ulong? nonce = null)
public async Task<IActionResult> Service(string serviceName, string cryptoCode, bool showQR = false, uint? nonce = null)
{
var service = GetService(serviceName, cryptoCode);
if (service == null)
@ -603,7 +603,7 @@ namespace BTCPayServer.Controllers
return View(nameof(LightningChargeServices), vm);
}
private IActionResult LndServices(ExternalService service, ExternalConnectionString connectionString, ulong? nonce, string view = nameof(LndServices))
private IActionResult LndServices(ExternalService service, ExternalConnectionString connectionString, uint? nonce, string view = nameof(LndServices))
{
var model = new LndServicesViewModel();
if (service.Type == ExternalServiceTypes.LNDGRPC)
@ -645,14 +645,14 @@ namespace BTCPayServer.Controllers
return View(view, model);
}
private static ulong GetConfigKey(string type, string serviceName, string cryptoCode, ulong nonce)
private static uint GetConfigKey(string type, string serviceName, string cryptoCode, uint nonce)
{
return ((ulong)(uint)HashCode.Combine(type, serviceName, cryptoCode, nonce) | (nonce & 0xffffffff00000000UL));
return (uint)HashCode.Combine(type, serviceName, cryptoCode, nonce);
}
[Route("lnd-config/{configKey}/lnd.config")]
[AllowAnonymous]
public IActionResult GetLNDConfig(ulong configKey)
public IActionResult GetLNDConfig(uint configKey)
{
var conf = _LnConfigProvider.GetConfig(configKey);
if (conf == null)
@ -712,7 +712,7 @@ namespace BTCPayServer.Controllers
commonConf.ReadonlyMacaroon = connectionString.Macaroons?.ReadonlyMacaroon?.Hex;
commonConf.InvoiceMacaroon = connectionString.Macaroons?.InvoiceMacaroon?.Hex;
var nonce = RandomUtils.GetUInt64();
var nonce = RandomUtils.GetUInt32();
var configKey = GetConfigKey("lnd", serviceName, cryptoCode, nonce);
_LnConfigProvider.KeepConfig(configKey, confs);
return RedirectToAction(nameof(Service), new { cryptoCode = cryptoCode, serviceName = serviceName, nonce = nonce });

View File

@ -305,11 +305,9 @@ namespace BTCPayServer.Controllers
derivationSchemeSettings.AccountOriginal = response.DerivationScheme.ToString();
// Set wallet properties from generate response
vm.RootFingerprint = response.AccountKeyPath.MasterFingerprint.ToString();
vm.AccountKey = response.AccountHDKey.Neuter().ToWif();
vm.KeyPath = response.AccountKeyPath.KeyPath.ToString();
vm.Config = ProtectString(derivationSchemeSettings.ToJson());
var result = await UpdateWallet(vm);
if (!ModelState.IsValid || !(result is RedirectToActionResult))

View File

@ -999,7 +999,7 @@ namespace BTCPayServer.Controllers
var appUrl = HttpContext.Request.GetAbsoluteRoot().WithTrailingSlash();
var model = new PayButtonViewModel
{
Price = null,
Price = 10,
Currency = DEFAULT_CURRENCY,
ButtonSize = 2,
UrlRoot = appUrl,

View File

@ -135,7 +135,7 @@ namespace BTCPayServer.Controllers
Name = store.StoreName,
WebSite = store.StoreWebsite,
IsOwner = store.Role == StoreRoles.Owner,
HintWalletWarning = blob.Hints.Wallet && blob.Hints.Lightning
HintWalletWarning = blob.Hints.Wallet
});
}
return View(result);

View File

@ -204,18 +204,10 @@ namespace BTCPayServer.Controllers
});
}
var command = vm.Command.Substring(vm.Command.IndexOf('-', StringComparison.InvariantCulture) + 1);
var handler = _payoutHandlers
.FirstOrDefault(handler => handler.CanHandle(paymentMethodId));
if (handler != null)
{
var result = await handler.DoSpecificAction(command, payoutIds, walletId.StoreId);
if (result != null)
{
TempData.SetStatusMessageModel(result);
}
}
switch (command)
{
case "approve-pay":
case "approve":
{
@ -272,7 +264,8 @@ namespace BTCPayServer.Controllers
{
Message = "Payouts approved", Severity = StatusMessageModel.StatusSeverity.Success
});
break;
return RedirectToAction(nameof(Payouts),
new {walletId = walletId.ToString(), pullPaymentId = vm.PullPaymentId});
}
case "pay":
@ -297,10 +290,7 @@ namespace BTCPayServer.Controllers
}
if(bip21.Any())
{
TempData.SetStatusMessageModel(null);
return RedirectToAction(nameof(WalletSend), new {walletId, bip21});
}
TempData.SetStatusMessageModel(new StatusMessageModel()
{
Severity = StatusMessageModel.StatusSeverity.Error,
@ -347,7 +337,8 @@ namespace BTCPayServer.Controllers
{
Message = "Payouts marked as paid", Severity = StatusMessageModel.StatusSeverity.Success
});
break;
return RedirectToAction(nameof(Payouts),
new {walletId = walletId.ToString(), pullPaymentId = vm.PullPaymentId});
}
case "cancel":
@ -357,10 +348,25 @@ namespace BTCPayServer.Controllers
{
Message = "Payouts archived", Severity = StatusMessageModel.StatusSeverity.Success
});
break;
return RedirectToAction(nameof(Payouts),
new {walletId = walletId.ToString(), pullPaymentId = vm.PullPaymentId});
}
return RedirectToAction(nameof(Payouts),
new {walletId = walletId.ToString(), pullPaymentId = vm.PullPaymentId});
var handler = _payoutHandlers
.FirstOrDefault(handler => handler.CanHandle(paymentMethodId));
if (handler != null)
{
var result = await handler.DoSpecificAction(command, payoutIds, walletId.StoreId);
TempData.SetStatusMessageModel(result);
return RedirectToAction(nameof(Payouts), new
{
walletId = walletId.ToString(),
pullPaymentId = vm.PullPaymentId
});
}
return NotFound();
}
private static async Task<List<PayoutData>> GetPayoutsForPaymentMethod(PaymentMethodId paymentMethodId,

View File

@ -489,13 +489,8 @@ namespace BTCPayServer.Controllers
.ToArray();
var balance = _walletProvider.GetWallet(network).GetBalance(paymentMethod.AccountDerivation);
model.NBXSeedAvailable = await GetSeed(walletId, network) != null;
var Balance= await balance;
model.CurrentBalance = (Balance.Available ?? Balance.Total).GetValue(network);
if (Balance.Immature is null)
model.ImmatureBalance = 0;
else
model.ImmatureBalance = Balance.Immature.GetValue(network);
model.CurrentBalance = (await balance).Total.GetValue(network);
await Task.WhenAll(recommendedFees);
model.RecommendedSatoshiPerByte =
recommendedFees.Select(tuple => tuple.Result).Where(option => option != null).ToList();
@ -630,23 +625,16 @@ namespace BTCPayServer.Controllers
}
transactionOutput.DestinationAddress = transactionOutput.DestinationAddress?.Trim() ?? string.Empty;
var inputName =
string.Format(CultureInfo.InvariantCulture, "Outputs[{0}].", i.ToString(CultureInfo.InvariantCulture)) +
nameof(transactionOutput.DestinationAddress);
try
{
var address = BitcoinAddress.Create(transactionOutput.DestinationAddress, network.NBitcoinNetwork);
if (address is TaprootAddress)
{
var supportTaproot = _dashboard.Get(network.CryptoCode)?.Status?.BitcoinStatus?.Capabilities?.CanSupportTaproot;
if (!(supportTaproot is true))
{
ModelState.AddModelError(inputName, "You need to update your full node, and/or NBXplorer (Version >= 2.1.56) to be able to send to a taproot address.");
}
}
BitcoinAddress.Create(transactionOutput.DestinationAddress, network.NBitcoinNetwork);
}
catch
{
var inputName =
string.Format(CultureInfo.InvariantCulture, "Outputs[{0}].", i.ToString(CultureInfo.InvariantCulture)) +
nameof(transactionOutput.DestinationAddress);
ModelState.AddModelError(inputName, "Invalid address");
}
@ -1070,8 +1058,7 @@ namespace BTCPayServer.Controllers
using CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
try
{
var b = await wallet.GetBalance(derivationStrategy, cts.Token);
return (b.Available ?? b.Total).ShowMoney(wallet.Network);
return (await wallet.GetBalance(derivationStrategy, cts.Token)).Total.ShowMoney(wallet.Network);
}
catch
{

View File

@ -70,11 +70,10 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
destination = destination.Trim();
try
{
// This doesn't work properly, (payouts are not detected), we can reactivate later when we fix the bug https://github.com/btcpayserver/btcpayserver/issues/2765
//if (destination.StartsWith($"{network.UriScheme}:", StringComparison.OrdinalIgnoreCase))
//{
// return Task.FromResult<IClaimDestination>(new UriClaimDestination(new BitcoinUrlBuilder(destination, network.NBitcoinNetwork)));
//}
if (destination.StartsWith($"{network.UriScheme}:", StringComparison.OrdinalIgnoreCase))
{
return Task.FromResult<IClaimDestination>(new UriClaimDestination(new BitcoinUrlBuilder(destination, network.NBitcoinNetwork)));
}
return Task.FromResult<IClaimDestination>(new AddressClaimDestination(BitcoinAddress.Create(destination, network.NBitcoinNetwork)));
}
@ -144,6 +143,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
{
{PayoutState.AwaitingPayment, new List<(string Action, string Text)>()
{
("confirm-payment", "Confirm payouts as paid"),
("reject-payment", "Reject payout transaction")
}}
};
@ -153,7 +153,7 @@ public class BitcoinLikePayoutHandler : IPayoutHandler
{
switch (action)
{
case "mark-paid":
case "confirm-payment":
await using (var context = _dbContextFactory.CreateContext())
{
var payouts = (await context.Payouts

View File

@ -43,13 +43,6 @@ namespace BTCPayServer.HostedServices
public bool Dirty => _Dirty;
public bool Unaffect => _Unaffect;
bool _IsBlobUpdated;
public bool IsBlobUpdated => _IsBlobUpdated;
public void BlobUpdated()
{
_IsBlobUpdated = true;
}
}
readonly InvoiceRepository _InvoiceRepository;
@ -90,26 +83,13 @@ namespace BTCPayServer.HostedServices
return;
if (invoice.Status == InvoiceStatusLegacy.New || invoice.Status == InvoiceStatusLegacy.Expired)
{
var isPaid = invoice.IsUnsetTopUp() ?
accounting.Paid > Money.Zero :
accounting.Paid >= accounting.MinimumTotalDue;
if (isPaid)
if (accounting.Paid >= accounting.MinimumTotalDue)
{
if (invoice.Status == InvoiceStatusLegacy.New)
{
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.PaidInFull));
invoice.Status = InvoiceStatusLegacy.Paid;
if (invoice.IsUnsetTopUp())
{
invoice.ExceptionStatus = InvoiceExceptionStatus.None;
invoice.Price = (accounting.Paid - accounting.NetworkFeeAlreadyPaid).ToDecimal(MoneyUnit.BTC) * paymentMethod.Rate;
accounting = paymentMethod.Calculate();
context.BlobUpdated();
}
else
{
invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? InvoiceExceptionStatus.PaidOver : InvoiceExceptionStatus.None;
}
invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? InvoiceExceptionStatus.PaidOver : InvoiceExceptionStatus.None;
context.UnaffectAddresses();
context.MarkDirty();
}
@ -313,10 +293,6 @@ namespace BTCPayServer.HostedServices
await _InvoiceRepository.UpdateInvoiceStatus(invoice.Id, invoice.GetInvoiceState());
updateContext.Events.Insert(0, new InvoiceDataChangedEvent(invoice));
}
if (updateContext.IsBlobUpdated)
{
await _InvoiceRepository.UpdateInvoicePrice(invoice.Id, invoice);
}
foreach (var evt in updateContext.Events)
{

View File

@ -150,11 +150,7 @@ namespace BTCPayServer.Hosting
foreach (var paymentMethod in store.GetSupportedPaymentMethods(_NetworkProvider).OfType<DerivationSchemeSettings>())
{
paymentMethod.IsHotWallet = paymentMethod.Source == "NBXplorer";
if (paymentMethod.IsHotWallet)
{
paymentMethod.Source = "NBXplorerGenerated";
store.SetSupportedPaymentMethod(paymentMethod);
}
paymentMethod.Source = "NBXplorerGenerated";
}
}
await ctx.SaveChangesAsync();

View File

@ -51,7 +51,7 @@ namespace BTCPayServer.ModelBinders
// Parse() method trims the value (with common NumberStyles) then throws if the result is empty.
model = null;
}
else if (type == typeof(decimal) || type == typeof(decimal?))
else if (type == typeof(decimal))
{
model = decimal.Parse(value, _supportedStyles, culture);
}

View File

@ -29,7 +29,7 @@ namespace BTCPayServer.Models.AppViewModels
public string NotificationUrl { get; set; }
[Required]
[Display(Name = "Make Crowdfund Public")]
[Display(Name = "Allow crowdfund to be publicly visible (still visible to you)")]
public bool Enabled { get; set; } = false;
[Required]
@ -44,13 +44,9 @@ namespace BTCPayServer.Models.AppViewModels
[Display(Name = "Enable Disqus Comments")]
public bool DisqusEnabled { get; set; } = true;
[Display(Name = "Disqus Shortname")]
public string DisqusShortname { get; set; }
[Display(Name = "Start date")]
[Display(Name = "Disqus Shortname")] public string DisqusShortname { get; set; }
public DateTime? StartDate { get; set; }
[Display(Name = "End date")]
public DateTime? EndDate { get; set; }
[Required]
@ -58,17 +54,19 @@ namespace BTCPayServer.Models.AppViewModels
[Display(Name = "Primary currency used for targets and stats. (e.g. BTC, LTC, USD, etc.)")]
public string TargetCurrency { get; set; } = "BTC";
[Display(Name = "Set a target amount")]
[Display(Name = "Set a Target amount ")]
[Range(0, double.PositiveInfinity)]
public decimal? TargetAmount { get; set; }
public IEnumerable<string> ResetEveryValues = Enum.GetNames(typeof(CrowdfundResetEvery));
[Display(Name = "Reset goal every")]
public string ResetEvery { get; set; } = nameof(CrowdfundResetEvery.Never);
public int ResetEveryAmount { get; set; } = 1;
[Display(Name = "Do not allow additional contributions after target has been reached")]
public bool EnforceTargetAmount { get; set; }
@ -82,7 +80,7 @@ namespace BTCPayServer.Models.AppViewModels
[Display(Name = "Custom CSS Code")]
public string EmbeddedCSS { get; set; }
[Display(Name = "Count all invoices created on the store as part of the goal")]
[Display(Name = "Count all invoices created on the store as part of the crowdfunding goal")]
public bool UseAllStoreInvoices { get; set; }
public string AppId { get; set; }
@ -90,13 +88,12 @@ namespace BTCPayServer.Models.AppViewModels
[Display(Name = "Sort contribution perks by popularity")]
public bool SortPerksByPopularity { get; set; }
[Display(Name = "Display contribution ranking")]
public bool DisplayPerksRanking { get; set; }
[Display(Name = "Sounds to play when a payment is made. One sound per line")]
public string Sounds { get; set; }
[Display(Name = "Colors to rotate between with animation when a payment is made. First color is the default background. One color per line. Can be any valid css color value.")]
public string AnimationColors { get; set; }

View File

@ -51,7 +51,7 @@ namespace BTCPayServer.Models
[JsonProperty(PropertyName = "currency", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string Currency { get; set; }
[JsonProperty(PropertyName = "price", DefaultValueHandling = DefaultValueHandling.Ignore)]
public decimal? Price { get; set; }
public decimal Price { get; set; }
[JsonProperty(PropertyName = "notificationEmail", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string NotificationEmail { get; set; }
[JsonConverter(typeof(DateTimeJsonConverter))]

View File

@ -14,6 +14,7 @@ namespace BTCPayServer.Models.InvoicingModels
Currency = "USD";
}
[Required]
public decimal? Amount
{
get; set;

View File

@ -27,7 +27,6 @@ namespace BTCPayServer.Models.InvoicingModels
public string DefaultLang { get; set; }
public List<AvailableCrypto> AvailableCryptos { get; set; } = new List<AvailableCrypto>();
public bool IsModal { get; set; }
public bool IsUnsetTopUp { get; set; }
public string CryptoCode { get; set; }
public string InvoiceId { get; set; }
public string BtcAddress { get; set; }

View File

@ -159,7 +159,6 @@ namespace BTCPayServer.Models.PaymentRequestViewModels
public DateTime ReceivedDate { get; set; }
public string Link { get; set; }
public string Id { get; set; }
public string Destination { get; set; }
}
}
}

View File

@ -1,5 +1,4 @@
using System;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Services;
namespace BTCPayServer.Models.ServerViewModels
@ -24,7 +23,7 @@ namespace BTCPayServer.Models.ServerViewModels
{
if (Settings?.LastUpdated is DateTimeOffset date)
{
return ViewsRazor.ToTimeAgo(date);
return Views.ViewsRazor.ToTimeAgo(date);
}
return null;
}

View File

@ -6,7 +6,8 @@ namespace BTCPayServer.Models.ServerViewModels
public class ViewFilesViewModel
{
public List<StoredFile> Files { get; set; }
public Dictionary<string, string> DirectUrlByFiles { get; set; }
public string DirectFileUrl { get; set; }
public string SelectedFileId { get; set; }
public bool StorageConfigured { get; set; }
}
}

View File

@ -9,7 +9,7 @@ namespace BTCPayServer.Models.StoreViewModels
public class PayButtonViewModel
{
[ModelBinder(BinderType = typeof(InvariantDecimalModelBinder))]
public decimal? Price { get; set; }
public decimal Price { get; set; }
public string InvoiceId { get; set; }
[Required]
public string Currency { get; set; }

View File

@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using BTCPayServer.Abstractions.Extensions;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.Services.Rates;
using BTCPayServer.Views;
using PullPaymentData = BTCPayServer.Data.PullPaymentData;
namespace BTCPayServer.Models

View File

@ -35,7 +35,6 @@ namespace BTCPayServer.Models.WalletViewModels
public bool SubtractFeesFromOutput { get; set; }
}
public decimal CurrentBalance { get; set; }
public decimal ImmatureBalance { get; set; }
public string CryptoCode { get; set; }

View File

@ -102,44 +102,6 @@ namespace BTCPayServer.PaymentRequest
Invoices = invoices.Select(entity =>
{
var state = entity.GetInvoiceState();
var payments = entity
.GetPayments(true)
.Select(paymentEntity =>
{
var paymentData = paymentEntity.GetCryptoPaymentData();
var paymentMethodId = paymentEntity.GetPaymentMethodId();
if (paymentData is null || paymentMethodId is null)
{
return null;
}
string txId = paymentData.GetPaymentId();
string link = GetTransactionLink(paymentMethodId, txId);
var paymentMethod = entity.GetPaymentMethod(paymentMethodId);
var amount = paymentData.GetValue();
var rate = paymentMethod.Rate;
var paid = (amount - paymentEntity.NetworkFee) * rate;
return new ViewPaymentRequestViewModel.PaymentRequestInvoicePayment
{
Amount = amount,
Paid = paid,
ReceivedDate = paymentEntity.ReceivedTime.DateTime,
PaidFormatted = _currencies.FormatCurrency(paid, blob.Currency),
RateFormatted = _currencies.FormatCurrency(rate, blob.Currency),
PaymentMethod = paymentMethodId.ToPrettyString(),
Link = link,
Id = txId,
Destination = paymentData.GetDestination()
};
})
.Where(payment => payment != null)
.ToList();
if (state.Status == InvoiceStatusLegacy.Invalid ||
state.Status == InvoiceStatusLegacy.Expired && !payments.Any())
return null;
return new ViewPaymentRequestViewModel.PaymentRequestInvoice
{
Id = entity.Id,
@ -149,11 +111,40 @@ namespace BTCPayServer.PaymentRequest
ExpiryDate = entity.ExpirationTime.DateTime,
State = state,
StateFormatted = state.ToString(),
Payments = payments
Payments = entity
.GetPayments(true)
.Select(paymentEntity =>
{
var paymentData = paymentEntity.GetCryptoPaymentData();
var paymentMethodId = paymentEntity.GetPaymentMethodId();
if (paymentData is null || paymentMethodId is null)
{
return null;
}
string txId = paymentData.GetPaymentId();
string link = GetTransactionLink(paymentMethodId, txId);
var paymentMethod = entity.GetPaymentMethod(paymentMethodId);
var amount = paymentData.GetValue();
var rate = paymentMethod.Rate;
var paid = (amount - paymentEntity.NetworkFee) * rate;
return new ViewPaymentRequestViewModel.PaymentRequestInvoicePayment
{
Amount = amount,
Paid = paid,
ReceivedDate = paymentEntity.ReceivedTime.DateTime,
PaidFormatted = _currencies.FormatCurrency(paid, blob.Currency),
RateFormatted = _currencies.FormatCurrency(rate, blob.Currency),
PaymentMethod = paymentMethodId.ToPrettyString(),
Link = link,
Id = txId
};
})
.Where(payment => payment != null)
.ToList()
};
})
.Where(invoice => invoice != null)
.ToList()
}).ToList()
};
}

View File

@ -413,7 +413,7 @@ namespace BTCPayServer.Payments.PayJoin
if (additionalFee > Money.Zero)
{
// If the user overpaid, taking fee on our output (useful if sender dump a full UTXO for privacy)
for (int i = 0; i < newTx.Outputs.Count && additionalFee > Money.Zero && due < Money.Zero && !invoice.IsUnsetTopUp(); i++)
for (int i = 0; i < newTx.Outputs.Count && additionalFee > Money.Zero && due < Money.Zero; i++)
{
if (disableoutputsubstitution)
break;

View File

@ -55,14 +55,11 @@ namespace BTCPayServer.Plugins
continue;
}
detectedPlugins = detectedPlugins.Select(plugin =>
foreach (var btcPayServerPlugin in detectedPlugins)
{
plugin.SystemPlugin = true;
return plugin;
});
loadedPlugins.Add((null,systemExtension, CreateEmbeddedFileProviderForAssembly(systemExtension)));
btcPayServerPlugin.SystemPlugin = true;
loadedPlugins.Add((null,systemExtension, CreateEmbeddedFileProviderForAssembly(systemExtension)));
}
plugins.AddRange(detectedPlugins);
}
var orderFilePath = Path.Combine(pluginsFolder, "order");

View File

@ -13,7 +13,6 @@ using NBitcoin.DataEncoders;
using NBitpayClient;
using NBXplorer;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
@ -397,10 +396,6 @@ namespace BTCPayServer.Services.Invoices
public double PaymentTolerance { get; set; }
public bool Archived { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public InvoiceType Type { get; set; }
public bool IsExpired()
{
return DateTimeOffset.UtcNow > ExpirationTime;
@ -686,11 +681,6 @@ namespace BTCPayServer.Services.Invoices
throw new InvalidOperationException("Not a legacy invoice");
}
}
public bool IsUnsetTopUp()
{
return Type == InvoiceType.TopUp && Price == 0.0m;
}
}
public enum InvoiceStatusLegacy
@ -875,10 +865,6 @@ namespace BTCPayServer.Services.Invoices
/// </summary>
public Money NetworkFee { get; set; }
/// <summary>
/// Total amount of network fee to pay to the invoice
/// </summary>
public Money NetworkFeeAlreadyPaid { get; set; }
/// <summary>
/// Minimum required to be paid in order to accept invoice as paid
/// </summary>
public Money MinimumTotalDue { get; set; }
@ -1005,14 +991,13 @@ namespace BTCPayServer.Services.Invoices
var totalDueNoNetworkCost = Money.Coins(Extensions.RoundUp(totalDue, precision));
bool paidEnough = paid >= Extensions.RoundUp(totalDue, precision);
int txRequired = 0;
decimal networkFeeAlreadyPaid = 0.0m;
_ = ParentEntity.GetPayments(true)
.Where(p => paymentPredicate(p))
.OrderBy(p => p.ReceivedTime)
.Select(_ =>
{
var txFee = _.GetValue(paymentMethods, GetId(), _.NetworkFee, precision);
networkFeeAlreadyPaid += txFee;
paid += _.GetValue(paymentMethods, GetId(), null, precision);
if (!paidEnough)
{
@ -1044,7 +1029,6 @@ namespace BTCPayServer.Services.Invoices
accounting.Due = Money.Max(accounting.TotalDue - accounting.Paid, Money.Zero);
accounting.DueUncapped = accounting.TotalDue - accounting.Paid;
accounting.NetworkFee = accounting.TotalDue - totalDueNoNetworkCost;
accounting.NetworkFeeAlreadyPaid = Money.Coins(Extensions.RoundUp(networkFeeAlreadyPaid, precision));
// If the total due is 0, there is no payment tolerance to calculate
var minimumTotalDueSatoshi = accounting.TotalDue.Satoshi == 0
? 0

View File

@ -206,8 +206,7 @@ namespace BTCPayServer.Services.Invoices
textSearch.Add(invoice.Id);
textSearch.Add(invoice.InvoiceTime.ToString(CultureInfo.InvariantCulture));
if (!invoice.IsUnsetTopUp())
textSearch.Add(invoice.Price.ToString(CultureInfo.InvariantCulture));
textSearch.Add(invoice.Price.ToString(CultureInfo.InvariantCulture));
textSearch.Add(invoice.Metadata.OrderId);
textSearch.Add(invoice.StoreId);
textSearch.Add(invoice.Metadata.BuyerEmail);
@ -426,22 +425,6 @@ namespace BTCPayServer.Services.Invoices
await context.SaveChangesAsync().ConfigureAwait(false);
}
}
internal async Task UpdateInvoicePrice(string invoiceId, InvoiceEntity invoice)
{
if (invoice.Type != InvoiceType.TopUp)
throw new ArgumentException("The invoice type should be TopUp to be able to update invoice price", nameof(invoice));
using (var context = _ContextFactory.CreateContext())
{
var invoiceData = await context.FindAsync<Data.InvoiceData>(invoiceId).ConfigureAwait(false);
if (invoiceData == null)
return;
var blob = invoiceData.GetBlob(_Networks);
blob.Price = invoice.Price;
AddToTextSearch(context, invoiceData, new[] { invoice.Price.ToString(CultureInfo.InvariantCulture) });
invoiceData.Blob = ToBytes(blob, null);
await context.SaveChangesAsync().ConfigureAwait(false);
}
}
public async Task MassArchive(string[] invoiceIds)
{

View File

@ -1,10 +1,7 @@
using Newtonsoft.Json;
namespace BTCPayServer.Services
{
public class MigrationSettings
{
[JsonProperty("MigrateHotwalletProperty2")]
public bool MigrateHotwalletProperty { get; set; }
public bool MigrateU2FToFIDO2{ get; set; }
public bool UnreachableStoreCheck { get; set; }

View File

@ -21,12 +21,11 @@
<h2 class="mb-4">@ViewData["PageTitle"]</h2>
<form method="post">
<input type="hidden" asp-for="StoreId" />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="row">
<div class="col-lg-6">
<div class="row">
<div class="col-lg-12">
<form method="post">
<input type="hidden" asp-for="StoreId" />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="form-label" data-required></label>
<input asp-for="Title" class="form-control" required />
@ -37,15 +36,11 @@
<input asp-for="Tagline" class="form-control" />
<span asp-validation-for="Tagline" class="text-danger"></span>
</div>
</div>
<div class="col-lg-9">
<div class="form-group">
<label asp-for="Description" class="form-label" data-required></label>
<textarea asp-for="Description" rows="20" cols="40" class="form-control richtext"></textarea>
<span asp-validation-for="Description" class="text-danger"></span>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label asp-for="TargetCurrency" class="form-label" data-required></label>
<input asp-for="TargetCurrency" class="form-control" required />
@ -61,8 +56,7 @@
<div class="input-group">
<input type="datetime-local" asp-for="StartDate"
value="@(Model.StartDate?.ToString("u", CultureInfo.InvariantCulture))"
class="form-control flatdtpicker"
placeholder="No start date has been set" />
class="form-control flatdtpicker" placeholder="No start date has been set for this crowdfund" />
<button class="btn btn-secondary input-group-clear" type="button" title="Clear">
<span class="fa fa-times"></span>
</button>
@ -70,19 +64,6 @@
<span asp-validation-for="StartDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="EndDate" class="form-label"></label>
<div class="input-group">
<input type="datetime-local" asp-for="EndDate"
value="@(Model.EndDate?.ToString("u", CultureInfo.InvariantCulture))"
class="form-control flatdtpicker"
placeholder="No end date has been set" />
<button class="btn btn-secondary input-group-clear input-group-text" type="button" title="Clear">
<span class="fa fa-times"></span>
</button>
</div>
<span asp-validation-for="EndDate" class="text-danger"></span>
</div>
<div class="form-group mb-4">
<label asp-for="ResetEvery" class="form-label"></label>
<div class="input-group">
<input type="number" asp-for="ResetEveryAmount" placeholder="Amount" class="form-control">
@ -94,156 +75,133 @@
</select>
</div>
</div>
<div class="form-group mb-3">
<div class="d-flex align-items-center mb-3">
<input asp-for="Enabled" type="checkbox" class="btcpay-toggle me-2"/>
<label asp-for="Enabled" class="form-label mb-0"></label>
<div class="form-group">
<label asp-for="EndDate" class="form-label"></label>
<div class="input-group">
<input type="datetime-local" asp-for="EndDate"
value="@(Model.EndDate?.ToString("u", CultureInfo.InvariantCulture))"
class="form-control flatdtpicker"
placeholder="No end date has been set for this crowdfund" />
<button class="btn btn-secondary input-group-clear input-group-text" type="button" title="Clear">
<span class="fa fa-times"></span>
</button>
</div>
<span asp-validation-for="Enabled" class="text-danger"></span>
<div class="text-muted">The crowdfund is only visible to you. To make it visible to anyone else, enable this.</div>
<span asp-validation-for="EndDate" class="text-danger"></span>
</div>
</div>
<div class="col-lg-12">
<partial name="TemplateEditor" model="@(nameof(Model.PerksTemplate), "Perks")" />
</div>
<div class="col-lg-6">
<div class="form-group">
<label asp-for="PerksTemplate" class="form-label"></label>
<textarea asp-for="PerksTemplate" rows="10" cols="40" class="js-product-template form-control"></textarea>
<span asp-validation-for="PerksTemplate" class="text-danger"></span>
</div>
<h4 class="mt-5 mb-4">Contributions</h4>
<div class="form-check mb-3">
<input asp-for="SortPerksByPopularity" type="checkbox" class="form-check-input" />
<label asp-for="SortPerksByPopularity" class="form-check-label"></label>
<span asp-validation-for="SortPerksByPopularity" class="text-danger"></span>
<div class="form-group">
<label asp-for="CustomCSSLink" class="form-label"></label>
<a href="https://docs.btcpayserver.org/Theme/#2-bootstrap-themes" target="_blank" rel="noreferrer noopener">
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
</a>
<input asp-for="CustomCSSLink" class="form-control" />
<span asp-validation-for="CustomCSSLink" class="text-danger"></span>
</div>
<div class="form-check mb-3">
<input asp-for="DisplayPerksRanking" type="checkbox" class="form-check-input" />
<label asp-for="DisplayPerksRanking" class="form-check-label"></label>
<span asp-validation-for="DisplayPerksRanking" class="text-danger"></span>
<div class="form-group">
<label asp-for="MainImageUrl" class="form-label"></label>
<input asp-for="MainImageUrl" class="form-control" />
<span asp-validation-for="MainImageUrl" class="text-danger"></span>
</div>
<div class="form-check mb-3">
<input asp-for="EnforceTargetAmount" type="checkbox" class="form-check-input" />
<label asp-for="EnforceTargetAmount" class="form-check-label"></label>
<span asp-validation-for="EnforceTargetAmount" class="text-danger"></span>
<div class="form-group">
<label asp-for="EmbeddedCSS" class="form-label"></label>
<textarea asp-for="EmbeddedCSS" rows="10" cols="40" class="form-control"></textarea>
<span asp-validation-for="EmbeddedCSS" class="text-danger"></span>
</div>
<h4 class="mt-5 mb-4">Crowdfund Behavior</h4>
<div class="form-group">
<label asp-for="NotificationUrl" class="form-label"></label>
<input asp-for="NotificationUrl" class="form-control" />
<span asp-validation-for="NotificationUrl" class="text-danger"></span>
</div>
<div class="form-check">
<input asp-for="UseAllStoreInvoices" type="checkbox" class="form-check-input" />
<label asp-for="UseAllStoreInvoices" class="form-check-label"></label>
<span asp-validation-for="UseAllStoreInvoices" class="text-danger"></span>
</div>
<h4 class="mt-5 mb-4">Sound</h4>
<div class="form-group mb-3">
<div class="d-flex align-items-center mb-3">
<input asp-for="SoundsEnabled" type="checkbox" class="btcpay-toggle me-2" data-bs-toggle="collapse" data-bs-target="#SoundsEnabledSettings" aria-expanded="@Model.SoundsEnabled" aria-controls="SoundsEnabledSettings"/>
<label asp-for="SoundsEnabled" class="form-label mb-0"></label>
</div>
<span asp-validation-for="SoundsEnabled" class="text-danger"></span>
</div>
<div class="collapse @(Model.SoundsEnabled ? "show" : "")" id="SoundsEnabledSettings">
<div class="form-group mb-0 pb-3">
<label asp-for="Sounds" class="form-label"></label>
<textarea asp-for="Sounds" class="form-control"></textarea>
<span asp-validation-for="Sounds" class="text-danger"></span>
</div>
</div>
<h4 class="mt-5 mb-4">Animation</h4>
<div class="form-group mb-3">
<div class="d-flex align-items-center mb-3">
<input asp-for="AnimationsEnabled" type="checkbox" class="btcpay-toggle me-2" data-bs-toggle="collapse" data-bs-target="#AnimationsEnabledSettings" aria-expanded="@Model.AnimationsEnabled" aria-controls="AnimationsEnabledSettings"/>
<label asp-for="AnimationsEnabled" class="form-label mb-0"></label>
</div>
<span asp-validation-for="AnimationsEnabled" class="text-danger"></span>
</div>
<div class="collapse @(Model.AnimationsEnabled ? "show" : "")" id="AnimationsEnabledSettings">
<div class="form-group mb-0 pb-3">
<label asp-for="AnimationColors" class="form-label"></label>
<textarea asp-for="AnimationColors" class="form-control"></textarea>
<span asp-validation-for="AnimationColors" class="text-danger"></span>
</div>
</div>
<h4 class="mt-5 mb-4">Discussion</h4>
<div class="form-group mb-3">
<div class="d-flex align-items-center mb-3">
<input asp-for="DisqusEnabled" type="checkbox" class="btcpay-toggle me-2" data-bs-toggle="collapse" data-bs-target="#DisqusEnabledSettings" aria-expanded="@Model.DisqusEnabled" aria-controls="DisqusEnabledSettings"/>
<label asp-for="DisqusEnabled" class="form-label mb-0"></label>
</div>
<span asp-validation-for="DisqusEnabled" class="text-danger"></span>
</div>
<div class="collapse @(Model.DisqusEnabled ? "show" : "")" id="DisqusEnabledSettings">
<div class="form-group mb-0 pb-3">
<label asp-for="DisqusShortname" class="form-label"></label>
<input asp-for="DisqusShortname" class="form-control" />
<span asp-validation-for="DisqusShortname" class="text-danger"></span>
</div>
</div>
<h4 class="mt-5 mb-2">Additional Options</h4>
<div class="form-group">
<div class="accordion" id="accordion-dev-info">
<div class="accordion-item">
<h2 class="accordion-header" id="accordion-dev-info-appearance-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#accordion-dev-info-appearance" aria-expanded="false" aria-controls="accordion-dev-info-appearance">
Custom CSS
<vc:icon symbol="caret-down" />
</button>
</h2>
<div id="accordion-dev-info-appearance" class="accordion-collapse collapse" aria-labelledby="accordion-dev-info-redirect-header">
<div class="accordion-body">
<div class="form-group">
<label asp-for="CustomCSSLink" class="form-label"></label>
<a href="https://docs.btcpayserver.org/Theme/#2-bootstrap-themes" target="_blank" rel="noreferrer noopener">
<span class="fa fa-question-circle-o text-secondary" title="More information..."></span>
</a>
<input asp-for="CustomCSSLink" class="form-control" />
<span asp-validation-for="CustomCSSLink" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MainImageUrl" class="form-label"></label>
<input asp-for="MainImageUrl" class="form-control" />
<span asp-validation-for="MainImageUrl" class="text-danger"></span>
</div>
<div class="form-group mb-4">
<label asp-for="EmbeddedCSS" class="form-label"></label>
<textarea asp-for="EmbeddedCSS" rows="10" cols="40" class="form-control"></textarea>
<span asp-validation-for="EmbeddedCSS" class="text-danger"></span>
</div>
</div>
</div>
</div>
<div class="form-check">
<input asp-for="Enabled" type="checkbox" class="form-check-input" />
<label asp-for="Enabled" class="form-check-label"></label>
<span asp-validation-for="Enabled" class="text-danger"></span>
</div>
<div class="form-check">
<input asp-for="SortPerksByPopularity" type="checkbox" class="form-check-input" />
<label asp-for="SortPerksByPopularity" class="form-check-label"></label>
<span asp-validation-for="SortPerksByPopularity" class="text-danger"></span>
</div>
<div class="form-check">
<input asp-for="DisplayPerksRanking" type="checkbox" class="form-check-input" />
<label asp-for="DisplayPerksRanking" class="form-check-label"></label>
<span asp-validation-for="DisplayPerksRanking" class="text-danger"></span>
</div>
<div class="form-check">
<input asp-for="EnforceTargetAmount" type="checkbox" class="form-check-input" />
<label asp-for="EnforceTargetAmount" class="form-check-label"></label>
<span asp-validation-for="EnforceTargetAmount" class="text-danger"></span>
</div>
<div class="form-check">
<input asp-for="UseAllStoreInvoices" type="checkbox" class="form-check-input" />
<label asp-for="UseAllStoreInvoices" class="form-check-label"></label>
<span asp-validation-for="UseAllStoreInvoices" class="text-danger"></span>
</div>
<div class="form-check">
<input asp-for="SoundsEnabled" type="checkbox" class="form-check-input" />
<label asp-for="SoundsEnabled" class="form-check-label"></label>
<span asp-validation-for="SoundsEnabled" class="text-danger"></span>
</div>
</div>
</div>
<div class="col-lg-9">
<div class="form-group">
<label asp-for="Sounds" class="form-label"></label>
<textarea asp-for="Sounds" class="form-control"></textarea>
<span asp-validation-for="Sounds" class="text-danger"></span>
</div>
<div class="form-group">
<div class="form-check">
<input asp-for="AnimationsEnabled" type="checkbox" class="form-check-input" />
<label asp-for="AnimationsEnabled" class="form-check-label"></label>
<span asp-validation-for="AnimationsEnabled" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="AnimationColors" class="form-label"></label>
<textarea asp-for="AnimationColors" class="form-control"></textarea>
<span asp-validation-for="AnimationColors" class="text-danger"></span>
</div>
<div class="form-group">
<div class="form-check">
<input asp-for="DisqusEnabled" type="checkbox" class="form-check-input" />
<label asp-for="DisqusEnabled" class="form-check-label"></label>
<span asp-validation-for="DisqusEnabled" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="DisqusShortname" class="form-label"></label>
<input asp-for="DisqusShortname" class="form-control" />
<span asp-validation-for="DisqusShortname" class="text-danger"></span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary" id="SaveSettings">Save Settings</button>
<div class="btn-group ms-2">
<div class="btn-group">
<a class="btn btn-outline-primary" asp-action="ListInvoices" asp-controller="Invoice" asp-route-searchterm="@Model.SearchTerm">Invoices</a>
<a class="btn btn-outline-primary" asp-action="ListInvoices" asp-controller="Invoice" asp-route-searchterm="@Model.SearchTerm"
target="viewinvoices_@Model.AppId"><span class="fa fa-external-link"></span></a>
</div>
@if (Model.ModelWithMinimumData)
{
<div class="btn-group ms-2">
<div class="btn-group">
<a class="btn btn-outline-primary" asp-action="ViewCrowdfund" asp-controller="AppsPublic" asp-route-appId="@Model.AppId" id="ViewApp">View App</a>
<a class="btn btn-outline-primary" asp-action="ViewCrowdfund" asp-controller="AppsPublic" asp-route-appId="@Model.AppId"
target="viewapp_@Model.AppId"><span class="fa fa-external-link"></span></a>
</div>
}
<div class="btn-group ms-2">
<div class="btn-group">
<a class="btn btn-outline-primary" asp-action="ListApps">Back to the app list</a>
<a class="btn btn-outline-primary" asp-action="ListApps" target="viewapp_@Model.AppId"><span class="fa fa-external-link"></span></a>
</div>
</div>
</div>
</form>
</div>
</form>
</div>
</div>
</section>

View File

@ -1,3 +1,2 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.Apps
@using BTCPayServer.Views.Apps
@using BTCPayServer.Models.AppViewModels

View File

@ -1,5 +1,4 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views
@using BTCPayServer.Views.Apps
@{
ViewBag.CategoryTitle = "Apps";

View File

@ -113,8 +113,10 @@
<div class="modal-content">
<div class="modal-header bg-primary text-white border-0">
<h5 class="modal-title">Confirmation</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" ref="close">
<vc:icon symbol="close" />
<button type="button" class="close text-white" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true">
<i class="fa fa-times fa-fw"></i>
</span>
</button>
</div>
<div class="modal-body p-0">
@ -256,7 +258,7 @@
</div>
<!-- Sidebar -->
<nav id="sidebar">
<nav id="sidebar" class="bg-dark text-white">
<div class="bg-primary p-3 clearfix">
<h3 class="text-white m-0 pull-left">Cart</h3>
<a class="js-cart btn btn-sm bg-white text-black pull-right ms-5" href="#">

View File

@ -1,5 +1,5 @@
@using BTCPayServer.Views.Stores
@using BTCPayServer.Abstractions.Extensions
@using Microsoft.AspNetCore.Mvc.Rendering
@using BTCPayServer.Views.Stores
@model UpdateCoinSwitchSettingsViewModel
@{
Layout = "../Shared/_NavLayout.cshtml";

View File

@ -1,5 +1,4 @@
@using BTCPayServer.Views.Stores
@using BTCPayServer.Abstractions.Extensions
@model BTCPayServer.Services.Altcoins.Ethereum.UI.EditEthereumPaymentMethodViewModel
@{

View File

@ -1,6 +1,5 @@
@using BTCPayServer.Views.Stores
@using BTCPayServer.Abstractions.Extensions
@model BTCPayServer.Services.Altcoins.Ethereum.UI.ViewEthereumStoreOptionsViewModel
@inject SignInManager<ApplicationUser> SignInManager;
@inject BTCPayNetworkProvider BTCPayNetworkProvider;

View File

@ -1,2 +1 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.Manage
@using BTCPayServer.Views.Manage

View File

@ -95,10 +95,10 @@
</div>
</div>
<div class="single-item-order__right">
<div class="single-item-order__right__btc-price" v-if="srvModel.status === 'paid' && !srvModel.isUnsetTopUp">
<div class="single-item-order__right__btc-price" v-if="srvModel.status === 'paid'">
<span>{{ srvModel.btcPaid }} {{ srvModel.cryptoCode }}</span>
</div>
<div class="single-item-order__right__btc-price" v-if="srvModel.status !== 'paid' && !srvModel.isUnsetTopUp">
<div class="single-item-order__right__btc-price" v-else>
<span>{{ srvModel.btcDue }} {{ srvModel.cryptoCode }}</span>
</div>
<div class="single-item-order__right__ex-rate" v-if="srvModel.orderAmountFiat && srvModel.cryptoCode">
@ -106,10 +106,10 @@
<span v-else>1 {{ srvModel.cryptoCodeSrv }} = {{ srvModel.rate }}</span>
</div>
</div>
<span class="fa fa-angle-double-down" v-if="!srvModel.isUnsetTopUp"></span>
<span class="fa fa-angle-double-up" v-if="!srvModel.isUnsetTopUp"></span>
<span class="fa fa-angle-double-down"></span>
<span class="fa fa-angle-double-up"></span>
</div>
<line-items v-if="!srvModel.isUnsetTopUp">
<line-items>
<div class="extraPayment" v-if="srvModel.status === 'new' && srvModel.txCount > 1">
{{$t("NotPaid_ExtraTransaction")}}
</div>

View File

@ -1,4 +1,4 @@
@model BTCPayServer.Models.InvoicingModels.CreateInvoiceModel
@model BTCPayServer.Models.InvoicingModels.CreateInvoiceModel
@{
ViewData.SetActivePageAndTitle(InvoiceNavPages.Create, "Create an invoice");
}
@ -35,8 +35,8 @@
<form asp-action="CreateInvoice" method="post" id="create-invoice-form">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Amount" class="form-label"></label>
<input asp-for="Amount" class="form-control" />
<label asp-for="Amount" class="form-label" data-required></label>
<input asp-for="Amount" class="form-control" required />
<span asp-validation-for="Amount" class="text-danger"></span>
</div>
<div class="form-group">

View File

@ -1,3 +1,2 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Services.Invoices
@using BTCPayServer.Services.Invoices
@using BTCPayServer.Views.Invoice

View File

@ -1,4 +1,3 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views.Invoice
@{

View File

@ -1,2 +1 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.Manage
@using BTCPayServer.Views.Manage

View File

@ -1,5 +1,4 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views
@using BTCPayServer.Views.Manage
@{
Layout = "../Shared/_NavLayout.cshtml";

View File

@ -1,5 +1,5 @@
@using BTCPayServer.Controllers
@using BTCPayServer.Views.Stores
@using BTCPayServer.Abstractions.Extensions
@model BTCPayServer.Services.Altcoins.Monero.UI.MoneroLikeStoreController.MoneroLikePaymentMethodViewModel
@{

View File

@ -1,5 +1,4 @@
@using BTCPayServer.Views.Stores
@using BTCPayServer.Abstractions.Extensions
@model BTCPayServer.Services.Altcoins.Monero.UI.MoneroLikeStoreController.MoneroLikePaymentMethodListViewModel
@{

View File

@ -1 +1 @@
@using BTCPayServer.Abstractions.Extensions


View File

@ -1,5 +1,4 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views
@using BTCPayServer.Views.Notifications
@{

View File

@ -9,27 +9,27 @@
ViewData["Title"] = Model.Title;
Layout = null;
var theme = await _settingsRepository.GetTheme();
string StatusClass(InvoiceState state)
string StatusTextClass(InvoiceState state)
{
switch (state.Status.ToModernStatus())
{
case InvoiceStatus.Settled:
case InvoiceStatus.Processing:
return "success";
return "text-success";
case InvoiceStatus.Expired:
switch (state.ExceptionStatus)
{
case InvoiceExceptionStatus.PaidLate:
case InvoiceExceptionStatus.PaidPartial:
case InvoiceExceptionStatus.PaidOver:
return "warning";
return "text-warning";
default:
return "danger";
return "text-danger";
}
case InvoiceStatus.Invalid:
return "danger";
return "text-danger";
default:
return "warning";
return "text-warning";
}
}
}
@ -56,11 +56,6 @@
@*We need to make sure btcpay.js is not bundled, else it will not work if there is a RootPath*@
<script src="~/modal/btcpay.js" asp-append-version="true"></script>
@Safe.Raw(Model.EmbeddedCSS)
<style>
.invoice { margin-top: var(--btcpay-space-s); }
.invoice + .invoice { margin-top: var(--btcpay-space-m); }
.invoice .badge { font-size: var(--btcpay-font-size-s); }
</style>
<noscript>
<style>
.hide-when-js, [v-cloak] { display: block !important; }
@ -246,32 +241,30 @@
}
else
{
@foreach (var invoice in Model.Invoices)
{
<table class="invoice table">
<thead>
<tr class="table-borderless">
<th class="fw-normal text-secondary w-350px" scope="col">Invoice Id</th>
<th class="fw-normal text-secondary w-175px">Expiry</th>
<th class="fw-normal text-secondary text-end w-125px">Amount</th>
<th class="fw-normal text-secondary text-end w-125px"></th>
<th class="fw-normal text-secondary text-end">Status</th>
</tr>
</thead>
<tbody>
<tr class="table-borderless table-light">
<table class="table my-0">
<thead>
<tr class="table-borderless">
<th class="fw-normal text-secondary" scope="col">Invoice Id</th>
<th class="fw-normal text-secondary w-175px">Expiry</th>
<th class="fw-normal text-secondary text-end w-125px">Amount</th>
<th class="fw-normal text-secondary text-end w-125px"></th>
<th class="fw-normal text-secondary text-end">Status</th>
</tr>
</thead>
<tbody>
@foreach (var invoice in Model.Invoices)
{
<tr>
<td>@invoice.Id</td>
<td>@invoice.ExpiryDate.ToString("g")</td>
<td class="text-end">@invoice.AmountFormatted</td>
<td class="text-end"></td>
<td class="text-end text-print-default">
<span class="badge bg-@StatusClass(invoice.State)">@invoice.StateFormatted</span>
</td>
<td class="text-end text-print-default @StatusTextClass(invoice.State)">@invoice.StateFormatted</td>
</tr>
@if (invoice.Payments != null && invoice.Payments.Any())
if (invoice.Payments != null && invoice.Payments.Any())
{
<tr class="table-borderless table-light">
<th class="fw-normal text-secondary">Destination</th>
<th class="fw-normal text-secondary ps-3">Transaction Id</th>
<th class="fw-normal text-secondary">Received</th>
<th class="fw-normal text-secondary text-end">Paid</th>
<th class="fw-normal text-secondary text-end">Rate</th>
@ -280,30 +273,26 @@
@foreach (var payment in invoice.Payments)
{
<tr class="table-borderless table-light">
<td class="text-break"><code>@payment.Destination</code></td>
<td class="ps-3 text-break">
@if (!string.IsNullOrEmpty(payment.Link))
{
<a href="@payment.Link" class="text-print-default" rel="noreferrer noopener" target="_blank">@payment.Id</a>
}
else
{
<span>@payment.Id</span>
}
</td>
<td>@payment.ReceivedDate.ToString("g")</td>
<td class="text-end">@payment.PaidFormatted</td>
<td class="text-end">@payment.RateFormatted</td>
<td class="text-end text-nowrap">@payment.Amount @payment.PaymentMethod</td>
</tr>
<tr class="table-borderless table-light">
<td class="fw-normal" colspan="5">
<span class="text-secondary">Transaction Id:</span>
@if (!string.IsNullOrEmpty(payment.Link))
{
<a href="@payment.Link" class="text-print-default text-break" rel="noreferrer noopener" target="_blank">@payment.Id</a>
}
else
{
<span class="text-break">@payment.Id</span>
}
</td>
</tr>
}
}
</tbody>
</table>
}
}
</tbody>
</table>
}
</noscript>
@ -311,10 +300,10 @@
<p class="text-muted">No payments made yet.</p>
</template>
<template v-else>
<table v-for="invoice of srvModel.invoices" :key="invoice.id" class="invoice table">
<table class="table my-0">
<thead>
<tr class="table-borderless">
<th class="fw-normal text-secondary w-350px" scope="col">Invoice Id</th>
<th class="fw-normal text-secondary" scope="col">Invoice Id</th>
<th class="fw-normal text-secondary w-175px">Expiry</th>
<th class="fw-normal text-secondary text-end w-125px">Amount</th>
<th class="fw-normal text-secondary text-end w-125px"></th>
@ -322,38 +311,32 @@
</tr>
</thead>
<tbody>
<tr class="table-borderless table-light">
<td>{{invoice.id}}</td>
<td v-text="formatDate(invoice.expiryDate)"></td>
<td class="text-end">{{invoice.amountFormatted}}</td>
<td class="text-end"></td>
<td class="text-end text-print-default">
<span class="badge" :class="`bg-${statusClass(invoice.stateFormatted)}`">{{invoice.stateFormatted}}</span>
</td>
</tr>
<template v-if="invoice.payments && invoice.payments.length > 0">
<tr class="table-borderless table-light">
<th class="fw-normal text-secondary">Destination</th>
<th class="fw-normal text-secondary">Received</th>
<th class="fw-normal text-secondary text-end">Paid</th>
<th class="fw-normal text-secondary text-end">Rate</th>
<th class="fw-normal text-secondary text-end">Payment</th>
<template v-for="invoice of srvModel.invoices" :key="invoice.id">
<tr>
<td>{{invoice.id}}</td>
<td v-text="formatDate(invoice.expiryDate)"></td>
<td class="text-end">{{invoice.amountFormatted}}</td>
<td class="text-end"></td>
<td class="text-end text-print-default" :class="statusTextClass(invoice.stateFormatted)">{{invoice.stateFormatted}}</td>
</tr>
<template v-for="payment of invoice.payments">
<template v-if="invoice.payments && invoice.payments.length > 0">
<tr class="table-borderless table-light">
<td class="text-break"><code>{{payment.destination}}</code></td>
<th class="fw-normal text-secondary ps-3">Transaction Id</th>
<th class="fw-normal text-secondary">Received</th>
<th class="fw-normal text-secondary text-end">Paid</th>
<th class="fw-normal text-secondary text-end">Rate</th>
<th class="fw-normal text-secondary text-end">Payment</th>
</tr>
<tr v-for="payment of invoice.payments" class="table-borderless table-light">
<td class="ps-3 text-break">
<a v-if="payment.link" :href="payment.link" class="text-print-default" target="_blank" rel="noreferrer noopener">{{payment.id}}</a>
<span v-else>{{payment.id}}</span>
</td>
<td v-text="formatDate(payment.receivedDate)"></td>
<td class="text-end">{{payment.paidFormatted}}</td>
<td class="text-end">{{payment.rateFormatted}}</td>
<td class="text-end text-nowrap">{{payment.amount.noExponents()}} {{payment.paymentMethod}}</td>
</tr>
<tr class="table-borderless table-light">
<td class="fw-normal" colspan="5">
<span class="text-secondary">Transaction Id:</span>
<a v-if="payment.link" :href="payment.link" class="text-print-default" target="_blank" rel="noreferrer noopener">{{payment.id}}</a>
<span v-else>{{payment.id}}</span>
</td>
</tr>
</template>
</template>
</tbody>

View File

@ -1,2 +1 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.PaymentRequest
@using BTCPayServer.Views.PaymentRequest

View File

@ -1,4 +1,3 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views.PaymentRequest
@{

View File

@ -45,7 +45,7 @@ else
<td>@file.Timestamp.ToBrowserDate()</td>
<td>@file.ApplicationUser.UserName</td>
<td class="text-end">
<a href="@Url.Action("Files", "Server", new { fileIds = new string[] { file.Id} })">Get Link</a>
<a asp-action="Files" asp-route-fileId="@file.Id">Get Link</a>
- <a asp-action="CreateTemporaryFileUrl" asp-route-fileId="@file.Id">Get Temp Link</a>
- <a asp-action="DeleteFile" asp-route-fileId="@file.Id">Remove</a>
</td>
@ -63,38 +63,31 @@ else
}
@if(Model.DirectUrlByFiles!=null && Model.DirectUrlByFiles.Count > 0)
@if (!string.IsNullOrEmpty(Model.SelectedFileId))
{
foreach (KeyValuePair<string, string> fileUrlPair in Model.DirectUrlByFiles)
{
var fileId = fileUrlPair.Key;
var fileUrl = fileUrlPair.Value;
var file = Model.Files.Single(storedFile => storedFile.Id.Equals(fileId, StringComparison.InvariantCultureIgnoreCase));
<div class="card mb-2">
<div class="card-text">
<ul class="list-group list-group-flush">
<li class="list-group-item">
@file.FileName
</li>
<li class="list-group-item">
<strong>URL:</strong>
<a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@fileId" target="_blank">
@Url.Action("GetFile", "Storage", new
{
fileId = fileId
}, Context.Request.Scheme, Context.Request.Host.ToString())
</a>
</li>
<li class="list-group-item">
<strong>Direct URL:</strong>
<a href="@fileUrl" target="_blank" rel="noreferrer noopener">@fileUrl</a>
</li>
</ul>
</div>
var file = Model.Files.Single(storedFile => storedFile.Id.Equals(Model.SelectedFileId, StringComparison.InvariantCultureIgnoreCase));
<div class="card mb-2">
<div class="card-text">
<ul class="list-group list-group-flush">
<li class="list-group-item">
@file.FileName
</li>
<li class="list-group-item">
<strong>URL:</strong>
<a asp-action="GetFile" asp-controller="Storage" asp-route-fileId="@Model.SelectedFileId" target="_blank">
@Url.Action("GetFile", "Storage", new
{
fileId = Model.SelectedFileId
}, Context.Request.Scheme, Context.Request.Host.ToString())
</a>
</li>
<li class="list-group-item">
<strong>Direct URL:</strong>
<a href="@Model.DirectFileUrl" target="_blank" rel="noreferrer noopener">@Model.DirectFileUrl</a>
</li>
</ul>
</div>
}
</div>
}
@if (Model.StorageConfigured)

View File

@ -15,6 +15,10 @@
<div>
@if (Model.Uri == null) // if GRPC
{
<a href="https://www.pebble.indiesquare.me/" target="_blank" class="d-inline-block me-3 text-center" rel="noreferrer noopener">
<img src="~/img/pebblewallet.jpg" width="100" height="100" asp-append-version="true" alt="Pebble" />
<div class="mt-2">Pebble</div>
</a>
<a href="https://zaphq.io/" target="_blank" class="d-inline-block me-3 text-center" rel="noreferrer noopener">
<img src="~/img/zapwallet.jpg" width="100" height="100" asp-append-version="true" alt="Zap" />
<div class="mt-2">Zap</div>

View File

@ -1,3 +1,2 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.Server
@using BTCPayServer.Views.Server
@using BTCPayServer.Models.ServerViewModels

View File

@ -1,5 +1,4 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views
@using BTCPayServer.Views.Server
@{
Layout = "../Shared/_NavLayout.cshtml";

View File

@ -19,14 +19,14 @@
</div>
</div>
<div class="bp-view payment manual-flow" id="copy" v-bind:class="{ 'active': currentTab == 'copy'}">
<div class="manual__step-two__instructions" v-if="!srvModel.isUnsetTopUp">
<div class="manual__step-two__instructions">
<span v-html="$t('CompletePay_Body', srvModel)"></span>
</div>
<div class="copyLabelPopup">
<span>{{$t("Copied")}}</span>
</div>
<nav class="copyBox">
<div class="copySectionBox bottomBorder" v-if="!srvModel.isUnsetTopUp">
<div class="copySectionBox bottomBorder">
<label>{{$t("Amount")}}</label>
<div class="copyAmountText copy-cursor _copySpan">
<span>{{srvModel.btcDue}}</span> {{ srvModel.cryptoCode }}

View File

@ -1,6 +1,6 @@
@using BTCPayServer.Services.Altcoins.Ethereum.UI
@using BTCPayServer.Views.Server
@using System.Net.Http
@using BTCPayServer.Abstractions.Extensions
@model BTCPayServer.Services.Altcoins.Ethereum.Configuration.EthereumLikeConfiguration
@inject BTCPayNetworkProvider BTCPayNetworkProvider;
@inject IHttpClientFactory HttpClientFactory;

View File

@ -14,12 +14,6 @@
<span class="d-block mt-3">Square Crypto</span>
</a>
</div>
<div class="p-3 text-center" style="flex-basis:105px;">
<a href="https://www.bailliegifford.com" target="_blank" class="text-muted small" rel="noreferrer noopener">
<img src="~/img/bailliegifford.svg" alt="Sponsor Baillie Gifford" height="50" width="50" asp-append-version="true"/>
<span class="d-block mt-3">Baillie Gifford</span>
</a>
</div>
<div class="p-3 text-center" style="flex-basis:105px;">
<a href="https://www.pnxbet.com" target="_blank" class="text-muted small" rel="noreferrer noopener">
<img src="~/img/pnxbet.png" alt="Sponsor PNXBET" height="50" width="50" asp-append-version="true"/>

View File

@ -6,7 +6,6 @@
@using BTCPayServer.Views.PaymentRequest
@using BTCPayServer.Views.Wallets
@using BTCPayServer.Abstractions.Contracts
@using BTCPayServer.Abstractions.Extensions
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject RoleManager<IdentityRole> RoleManager

View File

@ -1,12 +1,13 @@
@using BTCPayServer.Views.Stores
@using BTCPayServer.Abstractions.Extensions
@model BTCPayServer.Plugins.Shopify.Models.ShopifySettings
@{
Layout = "../Shared/_NavLayout.cshtml";
ViewData["NavPartialName"] = "../Stores/_Nav";
ViewData.SetActivePageAndTitle(StoreNavPages.Integrations, "Integrations");
var shopifyCredsSet = Model?.IntegratedAt.HasValue is true;
var shopifyUrl = Model?.ShopifyUrl;
}

View File

@ -50,9 +50,6 @@
<input asp-for="Config" type="hidden"/>
<input asp-for="Confirmation" type="hidden"/>
<input asp-for="DerivationScheme" type="hidden"/>
<input asp-for="AccountKey" type="hidden" />
<input asp-for="RootFingerprint" type="hidden" />
<input asp-for="KeyPath" type="hidden" />
<div class="form-group">
<table class="table table-sm table-responsive-md">

View File

@ -28,7 +28,7 @@
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div>
<h4>Connect hardware&nbsp;wallet</h4>
<p class="mb-0 text-secondary">Import your public keys using our Vault application</p>
<p class="mb-0 text-secondary">Import your keys using our Vault application</p>
</div>
<small class="d-block text-primary mt-2 mt-lg-0">Recommended</small>
</div>
@ -41,7 +41,7 @@
</div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div>
<h4>Connect hardware&nbsp;wallet</h4>
<h4>Connect hardware wallet</h4>
<p class="mb-0">Please enable JavaScript for this option to be available</p>
</div>
<small class="d-block text-primary mt-2 mt-lg-0">Recommended</small>

View File

@ -58,9 +58,9 @@
<div class="row">
<div class="form-group col-md-8">
<label class="form-label">Price</label>
<input name="price" type="text" class="form-control" placeholder="(optional)"
<input name="price" type="text" class="form-control"
v-model="srvModel.price" v-on:change="inputChanges"
v-validate="'decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }">
v-validate="'required|decimal|min_value:0'" :class="{'is-invalid': errors.has('price') }">
<small class="text-danger">{{ errors.first('price') }}</small>
</div>
<div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">

View File

@ -1,3 +1,2 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.Stores
@using BTCPayServer.Views.Stores
@using BTCPayServer.Models.StoreViewModels

View File

@ -1,5 +1,4 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views
@using BTCPayServer.Views.Stores
@{

View File

@ -1,3 +1,2 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.Stores
@using BTCPayServer.Views.Stores
@using BTCPayServer.Models.StoreViewModels

View File

@ -1,4 +1,3 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views.Stores

View File

@ -3,7 +3,7 @@ using System.Globalization;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
namespace BTCPayServer.Abstractions.Extensions
namespace BTCPayServer.Views
{
public static class ViewsRazor
{

View File

@ -1,4 +1,4 @@
@addTagHelper *, BundlerMinifier.TagHelpers
@addTagHelper *, BundlerMinifier.TagHelpers
@using Microsoft.AspNetCore.Mvc.ModelBinding
@model WalletSendModel
@{
@ -33,7 +33,6 @@
<input type="hidden" asp-for="Fiat" />
<input type="hidden" asp-for="Rate" />
<input type="hidden" asp-for="CurrentBalance" />
<input type="hidden" asp-for="ImmatureBalance" />
<input type="hidden" asp-for="CryptoCode" />
<input type="hidden" name="BIP21" id="BIP21" />
@ -64,64 +63,52 @@
@if (Model.Outputs.Count == 1)
{
<div class="form-group">
<div class="d-flex align-items-center justify-content-between">
<label asp-for="Outputs[0].DestinationAddress" class="form-label"></label>
<button type="submit" name="command" value="add-output" class="d-inline-block ms-2 btn text-secondary btn-link p-0 mb-2">Add another destination</button>
</div>
<input asp-for="Outputs[0].DestinationAddress" class="form-control font-monospace" autofocus autocomplete="off" />
<label asp-for="Outputs[0].DestinationAddress" class="form-label"></label>
<input asp-for="Outputs[0].DestinationAddress" class="form-control font-monospace" />
<span asp-validation-for="Outputs[0].DestinationAddress" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Outputs[0].Amount" class="form-label"></label>
<div class="input-group">
<input asp-for="Outputs[0].Amount" type="number" step="any" min="0" asp-format="{0}" class="form-control output-amount hide-number-spin" />
<input asp-for="Outputs[0].Amount" type="number" step="any" min="0" asp-format="{0}" class="form-control output-amount" />
<div class="input-group-text fiat-value" style="display:none;">
<span class="input-group-text p-0">=</span>
<input type="number" class="input-group-text fiat-value-edit-input py-0 hide-number-spin" min="0" step="any" style="max-width:100px" />
<input type="number" class="input-group-text fiat-value-edit-input py-0" min="0" step="any" style="max-width:100px" />
<span class="input-group-text p-0">@Model.Fiat</span>
</div>
</div>
<span asp-validation-for="Outputs[0].Amount" class="text-danger"></span>
<p class="form-text text-secondary crypto-info">
Your available balance is
Your current balance is
<button type="button" class="crypto-balance-link btn btn-link p-0 align-baseline">@Model.CurrentBalance</button> <span>@Model.CryptoCode</span>.
@if (Model.ImmatureBalance > 0)
{
<span><br><span class="text-warning">⚠</span> @Model.ImmatureBalance @Model.CryptoCode are still immature and require additional confirmations.</span>
}
</p>
</div>
}
else
{
<div class="list-group list-group-flush mt-n3 mb-4">
<div class="list-group-item">
<h5 class="mb-0">Destinations</h5>
</div>
<div class="list-group mb-4">
@for (var index = 0; index < Model.Outputs.Count; index++)
{
<div class="list-group-item transaction-output-form px-0 py-4">
<div class="list-group-item transaction-output-form">
<div class="row">
<div class="col-sm-12 col-lg-10">
<div class="form-group">
<label asp-for="Outputs[index].DestinationAddress" class="form-label"></label>
<input asp-for="Outputs[index].DestinationAddress" class="form-control" autocomplete="off" />
<input asp-for="Outputs[index].DestinationAddress" class="form-control" />
<span asp-validation-for="Outputs[index].DestinationAddress" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Outputs[index].Amount" class="form-label"></label>
<div class="input-group">
<input asp-for="Outputs[index].Amount" type="number" min="0" step="any" asp-format="{0}" class="form-control output-amount hide-number-spin" />
<div class="input-group-text fiat-value" style="display:none;">
<span class="input-group-text p-0">=</span>
<input type="number" class="input-group-text fiat-value-edit-input py-0 hide-number-spin" min="0" step="any" style="max-width:100px" />
<span class="input-group-text p-0">@Model.Fiat</span>
</div>
<input asp-for="Outputs[index].Amount" type="number" step="any" asp-format="{0}" class="form-control output-amount" />
<span class="input-group-text fiat-value" style="display:none;"></span>
</div>
<p class="form-text text-secondary crypto-info mb-2">
Your available balance is
Your current balance is
<button type="button" class="crypto-balance-link btn btn-link p-0 align-baseline">@Model.CurrentBalance</button> <span>@Model.CryptoCode</span>.
@if (Model.ImmatureBalance > 0)
{
<span><br>Note: @Model.ImmatureBalance @Model.CryptoCode are still immature and require additional confirmations.</span>
}
</p>
<span asp-validation-for="Outputs[index].Amount" class="text-danger"></span>
</div>
@ -148,7 +135,7 @@
}
<div class="form-group my-4">
<label asp-for="FeeSatoshiPerByte" class="form-label"></label>
<input asp-for="FeeSatoshiPerByte" type="number" min="0" step="any" class="form-control" style="max-width:14ch;" />
<input asp-for="FeeSatoshiPerByte" type="number" step="any" class="form-control" style="max-width:14ch;" />
<span asp-validation-for="FeeSatoshiPerByte" class="text-danger"></span>
<span id="FeeRate-Error" class="text-danger"></span>
@if (Model.RecommendedSatoshiPerByte.Any())
@ -236,6 +223,7 @@
</div>
<div class="form-group d-flex mt-2">
<button type="submit" id="SignTransaction" name="command" value="@(Model.NBXSeedAvailable ? "nbx-seed" : "sign")" class="btn btn-primary">Sign transaction</button>
<button type="submit" name="command" value="add-output" class="ms-2 btn btn-secondary">Add another destination</button>
<button type="button" id="bip21parse" class="ms-2 btn btn-secondary" title="Paste BIP21/Address"><i class="fa fa-paste"></i></button>
<button type="button" id="scanqrcode" class="ms-2 btn btn-secondary only-for-js" data-bs-toggle="modal" data-bs-target="#scanModal" title="Scan BIP21/Address with camera"><i class="fa fa-camera"></i></button>
</div>

View File

@ -1,4 +1,3 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views.Wallets
@using BTCPayServer.Views.Wallets
@using BTCPayServer.Models.WalletViewModels
@addTagHelper *, BundlerMinifier.TagHelpers

View File

@ -1,5 +1,4 @@
@using BTCPayServer.Abstractions.Extensions
@using BTCPayServer.Views
@using BTCPayServer.Views
@using BTCPayServer.Views.Wallets
@{
ViewBag.CategoryTitle = "Wallets";

View File

@ -192,6 +192,7 @@
"wwwroot/vendor/vuejs/vue.min.js",
"wwwroot/vendor/babel-polyfill/polyfill.min.js",
"wwwroot/vendor/bc-ur/web-bundle.js",
"wwwroot/vendor/ur-registry/urlib.min.js",
"wwwroot/vendor/vue-qrcode-reader/VueQrcodeReader.umd.min.js",
"wwwroot/js/wallet/**/*.js"
],
@ -212,6 +213,7 @@
"wwwroot/vendor/vuejs/vue.min.js",
"wwwroot/vendor/vue-qrcode/vue-qrcode.min.js",
"wwwroot/vendor/bc-ur/web-bundle.js",
"wwwroot/vendor/ur-registry/urlib.min.js",
"wwwroot/vendor/vue-qrcode-reader/VueQrcodeReader.umd.min.js"
],
"minify": {

View File

@ -76,8 +76,7 @@
overflow-x: hidden;
overflow-y: auto;
z-index: 999;
color: var(--btcpay-white);
background: var(--btcpay-bg-dark);
background: #e1e6ea;
transition: all 0.3s;
-webkit-overflow-scrolling: touch;
}

View File

@ -1,113 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="bdbb9e96-7dd2-4000-9304-0bf8a661aad9"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 121.9 121.9"
style="enable-background:new 0 0 121.9 121.9;background:#FFF" xml:space="preserve">
<style type="text/css">
.st0{fill:#222221;}
.st1{fill:#272425;}
</style>
<polygon class="st0" points="93.4,49.9 93,51 90.7,51 90,52.5 92.2,52.5 91.8,53.6 89.6,53.6 88.6,56.1 86.5,56.1 88.9,49.9 "/>
<path class="st0" d="M98.5,49.8c1.7,0,2.9,0.9,2.1,3.1c-0.7,2-2.6,3.3-4.7,3.3c-2.2,0-2.8-1.3-2.1-3.2
C94.6,51.1,96.4,49.8,98.5,49.8 M96.3,55.2c0.4,0,1.1-0.2,1.8-2.2c0.7-1.8,0.6-2.2,0-2.2s-1.1,0.4-1.9,2.3
C95.7,54.4,95.6,55.2,96.3,55.2"/>
<path class="st0" d="M106.2,49.9c0.7-0.1,1.4,0,2,0.2c0.5,0.1,0.8,0.7,0.6,1.1c0,0.1,0,0.1-0.1,0.2c-0.4,0.8-1.2,1.4-2.1,1.6l0.9,3
h-2.4l-0.5-2.5h-0.2l-1,2.5h-2.1l2.4-6.2H106.2z M105.6,50.9l-0.7,1.8h0.2c0.6,0.1,1.2-0.3,1.3-0.9c0.3-0.7,0.1-0.9-0.6-0.9H105.6z"
/>
<path class="st0" d="M113.7,49.9c0.9-0.1,1.9,0.1,2.7,0.6c0.7,0.7,0.4,1.8,0.2,2.3c-0.5,1.4-1.6,2.5-3,3c-0.8,0.2-1.6,0.3-2.4,0.3
h-2l2.4-6.2L113.7,49.9z M113.3,50.9l-1.7,4.2h0.2c0.5,0,1.4,0.2,2.4-2.2c0.8-2,0.1-2-0.7-2L113.3,50.9z"/>
<polygon class="st0" points="37.6,49.9 35.2,56.1 33,56.1 35.4,49.9 "/>
<polygon class="st0" points="42.6,49.9 40.6,55 42.9,55 42.5,56.1 38,56.1 40.4,49.9 "/>
<polygon class="st0" points="48.6,49.9 46.6,55 48.9,55 48.5,56.1 44,56.1 46.4,49.9 "/>
<polygon class="st0" points="55.1,49.9 52.7,56.1 50.5,56.1 52.9,49.9 "/>
<polygon class="st0" points="62.5,49.9 62.1,51 59.7,51 59.2,52.3 61.3,52.3 60.9,53.4 58.8,53.4 58.1,55 60.5,55 60.1,56.1
55.5,56.1 57.9,49.9 "/>
<path class="st0" d="M73.2,51.1c-0.3-0.1-0.7-0.2-1.1-0.2c-1.6,0-2.4,1.6-2.6,2.2c-0.3,0.8-0.6,1.7,0.1,2c0.2,0.1,0.4,0.1,0.7,0.1
l0.6-1.5h-0.8l0.4-1h2.8l-1.2,2.9c-0.8,0.3-1.7,0.5-2.5,0.5c-2.3,0-3.2-1.3-2.5-3.1c0.9-2,2.9-3.3,5.1-3.2c0.6,0,1.2,0.1,1.8,0.3
L73.2,51.1z"/>
<polygon class="st0" points="79.3,49.9 76.9,56.1 74.7,56.1 77.1,49.9 "/>
<polygon class="st0" points="86.7,49.9 86.3,51 83.9,51 83.3,52.5 85.5,52.5 85,53.6 82.9,53.6 81.9,56.1 79.7,56.1 82.2,49.9 "/>
<path class="st0" d="M22.6,49.9c0.6,0,1.2,0.1,1.7,0.2c0.4,0.1,0.7,0.5,0.5,1c0,0.1,0,0.1-0.1,0.2c-0.4,0.8-1.2,1.4-2.2,1.5
c0.4,0,0.7,0.2,1,0.3c0.4,0.3,0.5,0.8,0.3,1.2c-0.4,0.8-1.2,1.4-2.1,1.6c-0.7,0.2-1.4,0.2-2.2,0.2h-2.2l2.4-6.2H22.6z M21.2,52.4
c0.2,0,0.5,0,0.7-0.1c0.3-0.1,0.5-0.4,0.6-0.7c0.1-0.3,0.1-0.5-0.1-0.6c-0.2-0.1-0.4-0.1-0.7-0.1h-0.3l-0.6,1.5H21.2z M20.2,55.1
c0.3,0,0.6,0,0.8-0.1c0.3-0.2,0.6-0.5,0.7-0.8c0.2-0.4,0.1-0.6-0.1-0.7c-0.2-0.1-0.5-0.1-0.8-0.1h-0.3l-0.7,1.8H20.2z"/>
<path class="st0" d="M30.9,49.9l0.4,6.2H29v-1.2h-2l-1,1.2h-1.6l5.2-6.2H30.9z M27.7,53.9H29v-1.7L27.7,53.9z"/>
<path class="st0" d="M0,52.5c0-9.4,27.5-16.9,61.5-16.9c29.9,0,54.8,5.9,60.4,13.7c-6.3-6.2-28.4-10.7-54.7-10.7
C36,38.6,10.7,45,10.7,52.9S36,67.2,67.2,67.2c23,0,42.9-3.5,51.7-8.5c-8.9,6.3-31.2,10.8-57.3,10.8C27.5,69.5,0,61.9,0,52.5"/>
<path class="st1" d="M32.4,79l-0.5,5.8c0,0.3,0,0.5,0,0.5c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.2,0.3,0.2c0.2,0.1,0.4,0.1,0.6,0.1
l-0.1,0.2h-2.7L30,86h0.1c0.2,0,0.4,0,0.5-0.2c0.1-0.1,0.2-0.2,0.2-0.3c0.1-0.2,0.1-0.5,0.1-0.8l0.1-0.9h-2l-0.7,1
c-0.1,0.1-0.2,0.3-0.3,0.5c0,0.1,0,0.2,0,0.3c0,0.1,0.1,0.2,0.1,0.3c0.1,0.1,0.3,0.1,0.4,0.1l-0.1,0.2h-2.1l0-0.2
c0.2,0,0.5-0.1,0.7-0.3c0.3-0.3,0.6-0.6,0.9-1l4.1-5.7L32.4,79z M31.4,80.8l-2,2.7h1.7L31.4,80.8z"/>
<path class="st1" d="M37.4,85c-0.3,0.4-0.7,0.7-1.1,0.9c-0.3,0.2-0.7,0.3-1.1,0.3c-0.4,0-0.8-0.1-1.1-0.4c-0.3-0.3-0.4-0.7-0.4-1.1
c0-0.5,0.2-1.1,0.4-1.5c0.3-0.5,0.7-0.9,1.2-1.2c0.4-0.3,0.9-0.5,1.5-0.5c0.3,0,0.6,0.1,0.8,0.2c0.2,0.1,0.3,0.3,0.3,0.6
c0,0.2-0.1,0.4-0.2,0.5C37.6,83,37.4,83,37.3,83c-0.1,0-0.2,0-0.3-0.1c-0.1-0.1-0.1-0.2-0.1-0.3c0-0.1,0-0.1,0-0.2
c0-0.1,0.1-0.1,0.2-0.2c0.1,0,0.1-0.1,0.2-0.2c0,0,0-0.1,0-0.1c0-0.1,0-0.1-0.1-0.2c-0.1-0.1-0.3-0.1-0.4-0.1c-0.4,0-0.7,0.1-1,0.4
c-0.4,0.3-0.6,0.6-0.8,1c-0.3,0.5-0.4,1-0.4,1.6c0,0.3,0.1,0.6,0.3,0.8c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.5-0.1,0.8-0.2
c0.3-0.2,0.6-0.4,0.9-0.7L37.4,85z"/>
<path class="st1" d="M40.8,80.2l-0.4,1.4h0.8l-0.1,0.3h-0.8l-0.9,3c-0.1,0.2-0.1,0.4-0.2,0.6c0,0,0,0.1,0,0.1c0,0,0.1,0,0.1,0
c0.1,0,0.2-0.1,0.3-0.2c0.2-0.2,0.4-0.4,0.5-0.6l0.2,0.1c-0.2,0.4-0.5,0.7-0.9,1c-0.2,0.1-0.4,0.2-0.6,0.2c-0.1,0-0.3,0-0.4-0.1
c-0.1-0.1-0.2-0.2-0.2-0.4c0-0.3,0.1-0.6,0.2-0.8l0.8-3h-0.8v-0.2c0.3-0.1,0.7-0.2,0.9-0.5c0.3-0.3,0.6-0.7,0.8-1.1L40.8,80.2z"/>
<path class="st1" d="M45.9,81.6L45,84.7c-0.1,0.3-0.2,0.6-0.2,0.9c0,0,0,0.1,0,0.1c0,0,0.1,0,0.1,0c0.1,0,0.1,0,0.2-0.1
c0.2-0.2,0.4-0.4,0.5-0.6l0.2,0.1c-0.2,0.4-0.5,0.7-0.8,0.9c-0.2,0.1-0.3,0.2-0.5,0.2c-0.1,0-0.2,0-0.3-0.1C44,86.1,44,86,44,85.9
c0-0.2,0-0.3,0.1-0.5c0.1-0.2,0.2-0.8,0.5-1.6c-0.4,0.7-0.9,1.4-1.5,2c-0.3,0.3-0.7,0.5-1.1,0.5c-0.1,0-0.3-0.1-0.4-0.2
c-0.1-0.1-0.2-0.3-0.2-0.4c0-0.4,0.1-0.8,0.2-1.2l0.5-1.6c0.1-0.2,0.1-0.5,0.2-0.7c0,0,0-0.1,0-0.1c0,0-0.1,0-0.1,0
c-0.1,0-0.2,0-0.2,0.1c-0.2,0.2-0.3,0.4-0.5,0.6l-0.2-0.2c0.2-0.3,0.5-0.6,0.8-0.9c0.2-0.1,0.4-0.2,0.6-0.2c0.1,0,0.2,0,0.3,0.1
c0.1,0.1,0.1,0.2,0.1,0.3c0,0.3-0.1,0.7-0.2,1l-0.5,1.7c-0.1,0.3-0.2,0.6-0.2,0.8c0,0.1,0,0.1,0.1,0.2c0,0,0.1,0.1,0.2,0.1
c0.2,0,0.3-0.1,0.4-0.2c0.3-0.2,0.5-0.5,0.7-0.8c0.3-0.3,0.5-0.7,0.8-1.1c0.3-0.5,0.5-1.1,0.6-1.6l0.1-0.4L45.9,81.6z"/>
<path class="st1" d="M51.1,81.5l-1,3.5L50,85.5c0,0,0,0.1,0,0.2c0,0,0,0.1,0,0.2c0,0,0.1,0,0.1,0c0.1,0,0.1,0,0.2-0.1
c0.2-0.2,0.4-0.4,0.5-0.6l0.2,0.1c-0.2,0.3-0.4,0.6-0.7,0.8c-0.2,0.2-0.4,0.3-0.7,0.3c-0.1,0-0.2,0-0.3-0.1
c-0.1-0.1-0.1-0.2-0.1-0.3c0-0.2,0-0.4,0.1-0.7l0.1-0.4c-0.3,0.5-0.7,0.9-1.2,1.2c-0.2,0.2-0.5,0.2-0.8,0.2c-0.3,0-0.5-0.1-0.7-0.3
c-0.2-0.2-0.3-0.5-0.3-0.8c0-0.6,0.2-1.2,0.5-1.7c0.3-0.6,0.7-1.1,1.2-1.4c0.3-0.3,0.7-0.4,1.1-0.4c0.2,0,0.4,0.1,0.5,0.2
c0.2,0.1,0.3,0.3,0.3,0.5l0.2-0.6L51.1,81.5z M49.3,81.8c-0.3,0-0.5,0.1-0.7,0.3c-0.4,0.4-0.7,0.8-0.9,1.3c-0.3,0.5-0.4,1-0.4,1.5
c0,0.2,0,0.4,0.2,0.6c0.1,0.1,0.2,0.2,0.4,0.2c0.4,0,0.8-0.3,1.2-0.8c0.5-0.6,0.8-1.4,0.9-2.2c0-0.2,0-0.4-0.2-0.6
C49.6,81.8,49.5,81.8,49.3,81.8z"/>
<path class="st1" d="M54.6,78.9L52.8,85c-0.1,0.2-0.1,0.4-0.1,0.6c0,0.1,0.1,0.2,0.2,0.2c0,0,0,0,0,0c0.1,0,0.2,0,0.2-0.1
c0.2-0.2,0.4-0.4,0.6-0.7l0.2,0.2c-0.2,0.4-0.5,0.7-0.9,1c-0.2,0.1-0.4,0.2-0.6,0.2c-0.1,0-0.2,0-0.3-0.1c-0.1-0.1-0.1-0.2-0.1-0.3
c0-0.3,0.1-0.5,0.2-0.8l1.4-4.8c0.1-0.2,0.1-0.4,0.2-0.7c0-0.1,0-0.2-0.1-0.2c-0.1-0.1-0.2-0.1-0.3-0.1c-0.1,0-0.2,0-0.3,0v-0.2
L54.6,78.9z"/>
<path class="st1" d="M59.6,86l0,0.2h-2.9l0.1-0.2c0.2,0,0.4,0,0.6-0.1c0.1,0,0.2-0.1,0.3-0.2c0.2-0.3,0.3-0.6,0.3-0.9l1.2-4.2
c0.1-0.3,0.1-0.5,0.2-0.8c0-0.1,0-0.2-0.1-0.2c-0.1-0.1-0.1-0.1-0.2-0.1c-0.2,0-0.4-0.1-0.5,0l0.1-0.2h2.7l-0.1,0.2
c-0.2,0-0.3,0-0.5,0.1c-0.1,0.1-0.3,0.2-0.4,0.3c-0.1,0.3-0.2,0.6-0.3,0.8l-1.2,4.2c-0.1,0.2-0.1,0.5-0.2,0.7c0,0.1,0,0.2,0.1,0.2
c0.1,0.1,0.1,0.1,0.2,0.1C59.2,85.9,59.4,86,59.6,86z"/>
<path class="st1" d="M62.8,81.5l-0.7,2.3c0.4-0.7,0.9-1.3,1.5-1.9c0.3-0.3,0.6-0.4,1-0.4c0.2,0,0.3,0.1,0.4,0.2
c0.1,0.1,0.2,0.3,0.2,0.4c0,0.3-0.1,0.6-0.2,0.8l-0.6,2.2c0,0.1-0.1,0.3-0.1,0.4c0,0,0,0.1,0,0.1c0,0,0.1,0,0.1,0
c0.1,0,0.1,0,0.2-0.1c0.2-0.2,0.4-0.4,0.6-0.7l0.2,0.1c-0.2,0.4-0.5,0.7-0.9,1c-0.2,0.1-0.3,0.2-0.5,0.2c-0.1,0-0.2,0-0.3-0.1
c-0.1-0.1-0.1-0.2-0.1-0.3c0-0.3,0.1-0.6,0.2-0.8l0.6-2.1c0.1-0.2,0.1-0.4,0.1-0.6c0-0.1-0.1-0.2-0.2-0.2c-0.1,0-0.2,0.1-0.3,0.1
c-0.3,0.2-0.6,0.5-0.8,0.8c-0.3,0.4-0.6,0.9-0.9,1.4c-0.2,0.3-0.3,0.7-0.4,1l-0.2,0.8h-0.8l0.9-3.2c0.1-0.2,0.1-0.5,0.2-0.7
c0-0.1,0-0.1-0.1-0.2C61.6,82,61.5,82,61.4,82h-0.2H61v-0.2L62.8,81.5z"/>
<path class="st1" d="M65.9,81.8l1.5-0.3c0.1,0.3,0.2,0.5,0.3,0.8c0.1,0.5,0.2,0.9,0.2,1.4c0,0.3,0.1,0.8,0.1,1.7
c0.4-0.5,0.7-0.8,0.8-0.9l0.8-1.1c0.1-0.1,0.2-0.3,0.2-0.5c0-0.1,0.1-0.2,0.1-0.3c0-0.1-0.1-0.2-0.2-0.3c-0.1-0.1-0.2-0.2-0.2-0.4
c0-0.1,0-0.2,0.1-0.3c0.1-0.1,0.2-0.1,0.3-0.1c0.1,0,0.3,0.1,0.4,0.2c0.1,0.1,0.2,0.3,0.2,0.4c0,0.2,0,0.3-0.1,0.5
c-0.1,0.3-0.3,0.7-0.5,0.9c-0.4,0.5-0.8,1-1.2,1.5c-0.1,0.1-0.4,0.5-1.1,1.2h-0.2c0-1.4-0.1-2.7-0.5-4.1c-0.1-0.2-0.2-0.3-0.4-0.3
C66.2,81.9,66.1,81.9,65.9,81.8L65.9,81.8z"/>
<path class="st1" d="M71.6,84.2c0,0.1,0,0.3,0,0.4c0,0.3,0.1,0.6,0.3,0.8c0.2,0.2,0.5,0.3,0.8,0.3c0.2,0,0.5,0,0.7-0.1
c0.4-0.2,0.7-0.4,1-0.7l0.1,0.2c-0.6,0.7-1.4,1.1-2.3,1.2c-0.4,0-0.8-0.1-1.1-0.5c-0.2-0.3-0.4-0.6-0.4-1c0-0.6,0.2-1.1,0.5-1.6
c0.3-0.5,0.7-0.9,1.2-1.2c0.4-0.3,0.9-0.4,1.5-0.4c0.3,0,0.6,0.1,0.8,0.2c0.2,0.1,0.3,0.3,0.3,0.5c0,0.3-0.1,0.6-0.3,0.8
c-0.4,0.4-0.8,0.7-1.3,0.8C72.7,84.1,72.2,84.2,71.6,84.2z M71.6,84c0.4,0,0.8-0.1,1.2-0.3c0.4-0.1,0.7-0.4,1-0.7
c0.2-0.2,0.3-0.5,0.3-0.7c0-0.1-0.1-0.3-0.2-0.3c-0.1-0.1-0.2-0.1-0.4-0.1c-0.4,0-0.8,0.2-1.1,0.5C72.1,82.8,71.8,83.4,71.6,84
L71.6,84z"/>
<path class="st1" d="M78.8,81.5l-0.3,1.6h-0.2c0-0.4-0.1-0.7-0.3-1c-0.2-0.2-0.4-0.3-0.7-0.3c-0.2,0-0.4,0.1-0.5,0.2
c-0.1,0.1-0.2,0.3-0.2,0.4c0,0.1,0,0.2,0.1,0.3c0.1,0.2,0.2,0.3,0.3,0.4c0.3,0.3,0.6,0.7,0.9,1.1c0.1,0.2,0.2,0.4,0.2,0.7
c0,0.4-0.2,0.7-0.4,0.9c-0.3,0.3-0.7,0.4-1.1,0.4c-0.3,0-0.6-0.1-0.8-0.2c-0.1,0-0.2-0.1-0.3-0.1c-0.2,0-0.3,0.1-0.3,0.2h-0.2
l0.3-1.7h0.2c0,0.4,0.1,0.8,0.3,1.1c0.2,0.2,0.5,0.3,0.8,0.3c0.2,0,0.4-0.1,0.6-0.2c0.1-0.1,0.2-0.3,0.2-0.5c0-0.1,0-0.3-0.1-0.4
c-0.2-0.3-0.4-0.6-0.6-0.8c-0.2-0.2-0.4-0.5-0.6-0.8C76,83.1,76,82.9,76,82.7c0-0.3,0.1-0.6,0.4-0.8c0.3-0.3,0.8-0.4,1.2-0.3
l0.3,0.1c0.1,0.1,0.2,0.1,0.3,0.1c0.2,0,0.3-0.1,0.4-0.2H78.8z"/>
<path class="st1" d="M81.8,80.2l-0.4,1.4h0.8l-0.1,0.3h-0.8l-0.9,3c-0.1,0.2-0.1,0.4-0.1,0.6c0,0,0,0.1,0,0.1c0,0,0.1,0,0.1,0
c0.1,0,0.2-0.1,0.3-0.2c0.2-0.2,0.4-0.4,0.5-0.6l0.2,0.1c-0.2,0.4-0.5,0.7-0.9,1c-0.2,0.1-0.4,0.2-0.6,0.2c-0.1,0-0.3,0-0.4-0.1
c-0.1-0.1-0.1-0.2-0.1-0.4c0-0.3,0.1-0.6,0.2-0.8l0.9-3h-0.8v-0.2c0.3-0.1,0.7-0.2,0.9-0.5c0.3-0.3,0.6-0.7,0.8-1.1L81.8,80.2z"/>
<path class="st1" d="M86.9,83.1c0,0.5-0.2,1-0.4,1.5c-0.3,0.5-0.7,0.9-1.1,1.2c-0.4,0.3-0.9,0.4-1.4,0.4c-0.4,0-0.8-0.1-1.2-0.5
c-0.3-0.3-0.5-0.7-0.4-1.2c0-0.5,0.2-1.1,0.4-1.5c0.3-0.5,0.7-0.9,1.2-1.2c0.4-0.3,0.9-0.4,1.4-0.4c0.4,0,0.8,0.1,1.1,0.5
C86.7,82.3,86.9,82.7,86.9,83.1z M86,82.8c0-0.3-0.1-0.5-0.2-0.7c-0.2-0.2-0.4-0.3-0.6-0.2c-0.5,0-1,0.4-1.4,1.1
c-0.4,0.6-0.6,1.4-0.6,2.1c0,0.3,0.1,0.5,0.2,0.8c0.2,0.2,0.4,0.3,0.6,0.3c0.5,0,0.9-0.3,1.3-1.1C85.8,84.3,86,83.5,86,82.8z"/>
<path class="st1" d="M87.8,81.8l1.8-0.3L88.8,84c0.4-0.8,1-1.5,1.6-2.1c0.2-0.2,0.4-0.3,0.7-0.3c0.1,0,0.2,0,0.3,0.1
c0.1,0.1,0.1,0.2,0.1,0.3c0,0.2-0.1,0.5-0.2,0.7c-0.1,0.1-0.2,0.2-0.3,0.2c-0.1,0-0.1,0-0.2-0.1c-0.1-0.1-0.1-0.1-0.1-0.2
c0-0.1,0-0.1-0.1-0.1c0,0-0.1,0-0.1,0c-0.1,0-0.1,0-0.2,0c-0.2,0.1-0.3,0.2-0.4,0.4c-0.3,0.4-0.6,0.8-0.9,1.3
c-0.2,0.2-0.3,0.5-0.4,0.8c-0.2,0.4-0.2,0.6-0.2,0.7l-0.2,0.7h-0.8l1-3.2c0.1-0.3,0.1-0.5,0.2-0.8c0-0.1,0-0.1-0.1-0.2
c-0.1-0.1-0.2-0.1-0.3-0.1h-0.4L87.8,81.8z"/>
<path class="st1" d="M95.2,81.5l-0.3,1.6h-0.2c0-0.4-0.1-0.7-0.3-1c-0.2-0.2-0.4-0.3-0.7-0.3c-0.2,0-0.4,0.1-0.5,0.2
c-0.1,0.1-0.2,0.3-0.2,0.4c0,0.1,0,0.2,0.1,0.3c0.1,0.2,0.2,0.3,0.3,0.4c0.3,0.3,0.6,0.7,0.9,1.1c0.1,0.2,0.2,0.4,0.2,0.7
c0,0.4-0.2,0.7-0.4,0.9c-0.3,0.3-0.7,0.4-1.1,0.4c-0.3,0-0.6-0.1-0.8-0.2c-0.1,0-0.2-0.1-0.3-0.1c-0.2,0-0.3,0.1-0.3,0.2h-0.2
l0.3-1.7h0.2c0,0.4,0.1,0.8,0.3,1.1c0.2,0.2,0.5,0.3,0.8,0.3c0.2,0,0.4-0.1,0.6-0.2c0.1-0.1,0.2-0.3,0.2-0.5c0-0.1,0-0.3-0.1-0.4
c-0.2-0.3-0.4-0.6-0.6-0.8c-0.2-0.2-0.4-0.5-0.6-0.8c-0.1-0.2-0.1-0.4-0.1-0.5c0-0.3,0.1-0.6,0.4-0.8c0.3-0.2,0.6-0.4,0.9-0.3
c0.1,0,0.2,0,0.3,0l0.3,0.1c0.1,0,0.2,0.1,0.3,0.1c0.2,0,0.3-0.1,0.4-0.2L95.2,81.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,7 +1,7 @@
{
"NOTICE_WARN": "THIS CODE HAS BEEN AUTOMATICALLY GENERATED FROM TRANSIFEX, IF YOU WISH TO HELP TRANSLATION COME ON THE SLACK http://slack.btcpayserver.org TO REQUEST PERMISSION TO https://www.transifex.com/btcpayserver/btcpayserver/",
"code": "bg-BG",
"currentLanguage": "български",
"currentLanguage": "Английски",
"lang": "Език",
"Awaiting Payment...": "Очаква се платеж...",
"Pay with": "Плати с",
@ -49,4 +49,4 @@
"Close": "Затвори",
"NotPaid_ExtraTransaction": "Фактурата не а платена изцяло. Моля пратете остатъка в допълнителна транзакция. ",
"Recommended_Fee": "Препоръчена тарифа: {{feeRate}} сат/байт (sat/byte)"
}
}

View File

@ -1,7 +1,7 @@
{
"NOTICE_WARN": "THIS CODE HAS BEEN AUTOMATICALLY GENERATED FROM TRANSIFEX, IF YOU WISH TO HELP TRANSLATION COME ON THE SLACK http://slack.btcpayserver.org TO REQUEST PERMISSION TO https://www.transifex.com/btcpayserver/btcpayserver/",
"code": "fi-FI",
"currentLanguage": "Suomi",
"currentLanguage": "Englanti",
"lang": "Kieli",
"Awaiting Payment...": "Odotaa maksua...",
"Pay with": "Maksa käyttämällä",
@ -49,4 +49,4 @@
"Close": "Sulje",
"NotPaid_ExtraTransaction": "Laskua ei ole maksettu kokonaan. Lähetä uusi maksu erääntyvän summan kattamiseksi.",
"Recommended_Fee": "Suositeltu siirtomaksu: {{feeRate}} sat/tavu"
}
}

View File

@ -1,52 +0,0 @@
{
"NOTICE_WARN": "THIS CODE HAS BEEN AUTOMATICALLY GENERATED FROM TRANSIFEX, IF YOU WISH TO HELP TRANSLATION COME ON THE SLACK http://slack.btcpayserver.org TO REQUEST PERMISSION TO https://www.transifex.com/btcpayserver/btcpayserver/",
"code": "he",
"currentLanguage": "עברית",
"lang": "שפה",
"Awaiting Payment...": "ממתין לתשלום...",
"Pay with": "תשלום עם",
"Contact and Refund Email": "דוא\"ל ליצירת קשר והחזר",
"Contact_Body": "נא להזין כתובת דוא\"ל למטה.\nאנחנו ניצור אתך קשר בכתובת זו במקרא של בעיה עם התשלום שלך.",
"Your email": "הדוא\"ל שלך",
"Continue": "המשך",
"Please enter a valid email address": "נא להזין כתובת דוא\"ל תקינה",
"Order Amount": "סה\"כ הזמנה",
"Network Cost": "עלות רשת",
"Already Paid": "כבר שולם",
"Due": "חוב",
"Scan": "סריקה",
"Copy": "העתקה",
"Conversion": "המרה",
"Open in wallet": "פתיחת ארנק",
"CompletePay_Body": "להשלים את התשלום, נא לשלוח {{btcDue}} {{cryptoCode}} לכתובת הבאה.",
"Amount": "סכום",
"Address": "כתובת",
"Copied": "הועתק",
"ConversionTab_BodyTop": "ניתן לשלם {{cryptoCode}} {{btcDue}} בעזרת שיטקוינים אחרים מאלו שהמוכר/ת מקבל/ת ישירות.",
"ConversionTab_BodyDesc": "שירות זה מסופק על ידי צד שלישי. שימו לב שאין לנו שליטה על איך ספקים יעבירו את הכסף שלך. החשבונית תחשב כשולמה רק כשהכספים מתקבלים על שרשרת הבלוקים של {{cryptocode}}.",
"ConversionTab_CalculateAmount_Error": "נסו שוב",
"ConversionTab_LoadCurrencies_Error": "נסו שוב",
"ConversionTab_Lightning": "לא קיימים ספקי המרה לתשלומים לרשת הברק.",
"ConversionTab_CurrencyList_Select_Option": "נא לבחור מטבע להמיר",
"Invoice expiring soon...": "חשבונית תפוג תוקף בקרוב...",
"Invoice expired": "חשבונית פגה תוקף",
"What happened?": "מה קרה?",
"InvoiceExpired_Body_1": "חשבונית זו פגה תוקף. חשבונית תקפה רק למשך {{maxTimeMinutes}} דקות.\nניתן לחזור אל {{storeName}} אם ברצונך לשלוח את תשלומך שוב.",
"InvoiceExpired_Body_2": "אם ניסית לשלוח תשלום, הוא תרם התקבל על ידי הרשת. עדיין לא קיבלנו את הכספים שלך.",
"InvoiceExpired_Body_3": "אם נקבל זאת במועד מאוחר יותר, אנחנו נטפל בהזמנתך, או ניצור קשר אתך להסדיר החזר...",
"Invoice ID": "מספר חשבונית",
"Order ID": "מספר הזמנה",
"Return to StoreName": "חזרה אל {{storeName}}",
"This invoice has been paid": "החשבונית שולמה",
"This invoice has been archived": "חשבונית זו נגנזה",
"Archived_Body": "נא לפנות לחנות למידע על הזמנה או סיוע",
"BOLT 11 Invoice": "חשבונית BOLT 11",
"Node Info": "מידע צומת",
"txCount": "{{count}} פעולה",
"txCount_plural": "{{count}} פעולות",
"Pay with CoinSwitch": "תשלום עם CoinSwitch",
"Pay with Changelly": "תשלום עם Changelly",
"Close": "סגירה",
"NotPaid_ExtraTransaction": "החשבונית לא שולמה במלואה. נא לשלוח תשלום נוסף לכיסוי סכום החוב.",
"Recommended_Fee": "עמלה מומלצת: {{feeRate}} סאט/בית"
}

View File

@ -1,7 +1,7 @@
{
"NOTICE_WARN": "THIS CODE HAS BEEN AUTOMATICALLY GENERATED FROM TRANSIFEX, IF YOU WISH TO HELP TRANSLATION COME ON THE SLACK http://slack.btcpayserver.org TO REQUEST PERMISSION TO https://www.transifex.com/btcpayserver/btcpayserver/",
"code": "kk-KZ",
"currentLanguage": "қазақ",
"currentLanguage": "Қазақша",
"lang": "Тіл",
"Awaiting Payment...": "Күтіп тұрған төлем…",
"Pay with": "Төлеу",
@ -49,4 +49,4 @@
"Close": "Close",
"NotPaid_ExtraTransaction": "The invoice hasn't been paid in full. Please send another transaction to cover amount Due.",
"Recommended_Fee": "Recommended fee: {{feeRate}} sat/byte"
}
}

View File

@ -1,52 +0,0 @@
{
"NOTICE_WARN": "THIS CODE HAS BEEN AUTOMATICALLY GENERATED FROM TRANSIFEX, IF YOU WISH TO HELP TRANSLATION COME ON THE SLACK http://slack.btcpayserver.org TO REQUEST PERMISSION TO https://www.transifex.com/btcpayserver/btcpayserver/",
"code": "ko",
"currentLanguage": "한국어",
"lang": "언어",
"Awaiting Payment...": "지불 대기 중...",
"Pay with": "Pay with",
"Contact and Refund Email": "연락 및 환불 이메일",
"Contact_Body": "Please provide an email address below. Well contact you at this address if there is an issue with your payment.",
"Your email": "자신의 이메일",
"Continue": "계속하기",
"Please enter a valid email address": "유효한 이메일 주소를 입력해주세요",
"Order Amount": "총 주문 금액",
"Network Cost": "네트워크 수수료",
"Already Paid": "지불 완료",
"Due": "지불 대기 중",
"Scan": "스캔",
"Copy": "복사",
"Conversion": "환율",
"Open in wallet": "지갑에서 열기",
"CompletePay_Body": "To complete your payment, please send {{btcDue}} {{cryptoCode}} to the address below.",
"Amount": "금액",
"Address": "주소",
"Copied": "복사 완료",
"ConversionTab_BodyTop": "You can pay {{btcDue}} {{cryptoCode}} using altcoins other than the ones merchant directly supports.",
"ConversionTab_BodyDesc": "This service is provided by 3rd party. Please keep in mind that we have no control over how providers will forward your funds. Invoice will only be marked paid once funds are received on {{cryptoCode}} Blockchain.",
"ConversionTab_CalculateAmount_Error": "다시 시도",
"ConversionTab_LoadCurrencies_Error": "다시 시도",
"ConversionTab_Lightning": "No conversion providers available for Lightning Network payments.",
"ConversionTab_CurrencyList_Select_Option": "환전할 화폐를 선택하세요",
"Invoice expiring soon...": "인보이스가 곧 만료 됨...",
"Invoice expired": "인보이스 만료",
"What happened?": "무슨 일인가요?",
"InvoiceExpired_Body_1": "This invoice has expired. An invoice is only valid for {{maxTimeMinutes}} minutes. \nYou can return to {{storeName}} if you would like to submit your payment again.",
"InvoiceExpired_Body_2": "If you tried to send a payment, it has not yet been accepted by the network. We have not yet received your funds.",
"InvoiceExpired_Body_3": "",
"Invoice ID": "인보이스 ID",
"Order ID": "주문 ID",
"Return to StoreName": "{{storeName}}으로 돌아가기",
"This invoice has been paid": "이 인보이스는 지불 완료됐습니다.",
"This invoice has been archived": "This invoice has been archived",
"Archived_Body": "Please contact the store for order information or assistance",
"BOLT 11 Invoice": "BOLT 11 인보이스",
"Node Info": "노드 정보",
"txCount": "{{count}} 거래",
"txCount_plural": "{{count}} 거래",
"Pay with CoinSwitch": "CoinSwitch를 이용해 지불하기",
"Pay with Changelly": "Changelly를 이용해 지불하기",
"Close": "닫기",
"NotPaid_ExtraTransaction": "The invoice hasn't been paid in full. Please send another transaction to cover amount Due.",
"Recommended_Fee": "추천하는 수수료: {{feeRate}} sat/byte"
}

View File

@ -3,13 +3,13 @@
"code": "nl-NL",
"currentLanguage": "Nederlands",
"lang": "Taal",
"Awaiting Payment...": "Wacht op betaling...",
"Pay with": "Betaal met",
"Contact and Refund Email": "E-mailadres voor opvolging en terugbetaling",
"Contact_Body": "Laat hieronder uw e-mailadres achter. We nemen contact met u op mochten er problemen zijn met uw betaling.",
"Your email": "Uw e-mailadres",
"Awaiting Payment...": "In afwachting van de betaling...",
"Pay with": "Betalen met",
"Contact and Refund Email": "Email adres voor opvolging en terugbetaling",
"Contact_Body": "Laat hieronder uw email adres achter. We nemen contact met u op als er problemen zijn met uw betaling.",
"Your email": "Je email adres",
"Continue": "Verder",
"Please enter a valid email address": "Vul een geldig e-mailadres in",
"Please enter a valid email address": "Vul een geldig email adres in",
"Order Amount": "Bedrag van uw bestelling",
"Network Cost": "Netwerkkosten",
"Already Paid": "Reeds betaald",
@ -18,24 +18,24 @@
"Copy": "Kopiëren",
"Conversion": "Omzetting",
"Open in wallet": "Wallet openen",
"CompletePay_Body": "Om de betaling af te ronden, stuur alstublieft {{btcDue}} {{cryptoCode}} naar het hieronder vermelde adres.",
"CompletePay_Body": "Om de betaling af te ronden, stuur alstublieft {{btcDue}} {{cryptoCode}} naar het hieronder vemelde adres.",
"Amount": "Bedrag",
"Address": "Adres",
"Copied": "Gekopieerd",
"ConversionTab_BodyTop": "U kunt altcoins gebruiken die niet ondersteund zijn door de verkoper, om {{btcDue}} {{cryptoCode}} te betalen.",
"ConversionTab_BodyDesc": "Deze dienst wordt door een 3e partij geleverd. Wij hebben daardoor geen zicht op uw fondsen. De factuur wordt pas als betaald beschouwd, wanneer de fondsen door de {{ cryptoCode }} blockchain aanvaard zijn.",
"ConversionTab_BodyDesc": "Deze dienst wordt door een 3e partij geleverd. Wij hebben daardoor geen zicht over uw fondsen. De factuur wordt pas als betaald beschouwd, wanneer de fondsen door de {{ cryptoCode }} blockchain aanvaard zijn.",
"ConversionTab_CalculateAmount_Error": "Opnieuw proberen",
"ConversionTab_LoadCurrencies_Error": "Opnieuw proberen",
"ConversionTab_Lightning": "Geen conversie leverancier beschikbaar voor de betalingen op het Lightning Network",
"ConversionTab_CurrencyList_Select_Option": "Selecteer een valuta om te converteren",
"Invoice expiring soon...": "Factuur verloopt binnenkort...",
"Invoice expired": "Factuur vervallen",
"What happened?": "Wat is er gebeurd?",
"InvoiceExpired_Body_1": "De factuur is vervallen. Een factuur is slechts geldig voor {{maxTimeMinutes}} minuten. \nU kan teruggaan naar {{storeName}} als u de betaling opnieuw wil proberen.",
"InvoiceExpired_Body_2": "Als u een betaling uitvoerde, dan werd deze nog niet bevestigd door het netwerk. We hebben uw betaling nog niet ontvangen.",
"InvoiceExpired_Body_3": "Als we uw betaling later ontvangen, zullen we uw order verwerken of nemen we contact op om een terugbetaling te regelen...",
"Invoice expiring soon...": "De factuur verloopt binnenkort...",
"Invoice expired": "Vervallen factuur",
"What happened?": "Wat gebeurde er?",
"InvoiceExpired_Body_1": "De factuur is vervallen. Een factuur is alleen geldig voor {{maxTimeMinutes}} minuten. \nJe kan terug komen naar {{storeName}} als je de betaling opnieuw wilt proberen",
"InvoiceExpired_Body_2": "Als u een betaling uitvoerde, dan werd dit nog niet bevestigd door het netwerk. We hebben uw fondsen nog niet ontvangen.",
"InvoiceExpired_Body_3": "Indien we het later ontvangen, zullen we uw order verwerken of nemen we contact op om een terugbetaling te regelen...",
"Invoice ID": "Factuurnummer",
"Order ID": "Ordernummer",
"Order ID": "Bestllingsnummer",
"Return to StoreName": "Terug naar {{storeName}}",
"This invoice has been paid": "Deze factuur is betaald",
"This invoice has been archived": "Deze factuur is gearchiveerd",

View File

@ -32,7 +32,7 @@
"Invoice expired": "Fatura expirada",
"What happened?": "O que aconteceu?",
"InvoiceExpired_Body_1": "Esta fatura expirou. Uma fatura é válida por apenas {{maxTimeMinutes}} minutos. \nVocê pode voltar para {{storeName}} se quiser tentar enviar o pagamento novamente.",
"InvoiceExpired_Body_2": "Se você tentou enviar um pagamento, ele ainda não foi aceito pela rede. Nós ainda não recebemos o valor enviado.",
"InvoiceExpired_Body_2": "Se você tentou enviar um pagamento e ele ainda não foi aceito pela rede Bitcoin. Nós ainda não recebemos o valor enviado.",
"InvoiceExpired_Body_3": "Se recebermos mais tarde, vamos processar o pedido ou entrar em contato para combinar o reembolso...",
"Invoice ID": "Nº da Fatura",
"Order ID": "Nº do Pedido",

View File

@ -217,12 +217,6 @@ h2 small .fa-question-circle-o {
.w-150px { width: 150px; }
.w-175px { width: 175px; }
.w-200px { width: 200px; }
.w-225px { width: 225px; }
.w-250px { width: 250px; }
.w-275px { width: 275px; }
.w-300px { width: 300px; }
.w-325px { width: 325px; }
.w-350px { width: 350px; }
/* Print */
@media print {
@ -230,7 +224,7 @@ h2 small .fa-question-circle-o {
.table th {
background: transparent;
}
.bg-tile.h-100.p-3 {
.jumbotron {
padding: 1rem 0 !important;
}
.text-print-default {

View File

@ -45,8 +45,7 @@ document.addEventListener("DOMContentLoaded", function () {
maxDate: max,
defaultDate: defaultDate,
time_24hr: true,
defaultHour: 0,
static: true
defaultHour: 0
});
}
});

Some files were not shown because too many files have changed in this diff Show More