Compare commits

...

10 Commits

Author SHA1 Message Date
ca55e1f300 bump 2024-04-15 22:27:09 +09:00
8b02c0bd82 Prevent payout double send (#5931)
Fixes #5913.
2024-04-15 22:06:00 +09:00
b92ff7c27b Bump CLightning (#5923) 2024-04-15 18:22:51 +09:00
d24761a498 update csv export to include full date and time in 12 hour format (#5922)
* update csv export to include full date and time in 12 hour format

* formatting the export datetime to 24 hours
2024-04-15 12:22:18 +09:00
c78ee24d0a Fix: Unable to use a different postgres schema (Fix #5901) 2024-04-15 11:38:56 +09:00
172dd507bd Small payment request fixes (#5926)
* Do not crash payment request page on 0 amount

* set email from form to payment request
2024-04-15 09:11:19 +09:00
fdd4790023 (bug) handle null XMR settings (#5909)
Co-authored-by: Henry Hollingworth <henry.hollingworth@alcoa.com>
2024-04-15 09:11:08 +09:00
4ebe46830b Fix JSContent test 2024-04-09 11:13:07 +09:00
a2df9ed44c fix: switch to using get_info for monerod (#5885) 2024-04-09 11:12:38 +09:00
6ae474d214 Adding Tether as BTCPay Server Foundation Supporter (#5891)
* Adding Tether as BTCPay Server Foundation Supporter

* Adding Tether to _BTCPaySupporters partial as well

* Modfying supporter_strike.svg to have white backgroundf or dark mode

* Modifying supporter_tether.svg to fit in the 150x100 box

* Centering Tether shape
2024-04-09 11:12:06 +09:00
20 changed files with 131 additions and 57 deletions

View File

@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Options;
using Npgsql;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Operations;
@ -85,10 +86,9 @@ namespace BTCPayServer.Abstractions.Contracts
{
o.EnableRetryOnFailure(10);
o.SetPostgresVersion(12, 0);
if (!string.IsNullOrEmpty(_schemaPrefix))
{
o.MigrationsHistoryTable(_schemaPrefix);
}
var mainSearchPath = GetSearchPath(_options.Value.ConnectionString);
var schemaPrefix = string.IsNullOrEmpty(_schemaPrefix) ? "__EFMigrationsHistory" : _schemaPrefix;
o.MigrationsHistoryTable(schemaPrefix, mainSearchPath);
})
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
break;
@ -108,5 +108,11 @@ namespace BTCPayServer.Abstractions.Contracts
}
}
private string GetSearchPath(string connectionString)
{
var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString);
var searchPaths = connectionStringBuilder.SearchPath?.Split(',');
return searchPaths is not { Length: > 0 } ? null : searchPaths[0];
}
}
}

View File

@ -464,7 +464,7 @@ retry:
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "dom-confetti", "dom-confetti.min.js").Trim();
version = Regex.Match(actual, "Original file: /npm/dom-confetti@([0-9]+.[0-9]+.[0-9]+)/lib/main.js").Groups[1].Value;
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/dom-confetti@{version}/lib/main.min.js")).Content.ReadAsStringAsync()).Trim();
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/dom-confetti@{version}")).Content.ReadAsStringAsync()).Trim();
EqualJsContent(expected, actual);
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "vue-sortable", "sortable.min.js").Trim();

View File

@ -163,7 +163,7 @@ services:
- "bitcoin_datadir:/data"
customer_lightningd:
image: btcpayserver/lightning:v23.08-dev
image: btcpayserver/lightning:v24.02.2
stop_signal: SIGKILL
restart: unless-stopped
environment:
@ -171,6 +171,7 @@ services:
LIGHTNINGD_CHAIN: "btc"
LIGHTNINGD_NETWORK: "regtest"
LIGHTNINGD_OPT: |
developer
bitcoin-datadir=/etc/bitcoin
bitcoin-rpcconnect=bitcoind
announce-addr=customer_lightningd:9735
@ -190,13 +191,14 @@ services:
- bitcoind
merchant_lightningd:
image: btcpayserver/lightning:v23.08-dev
image: btcpayserver/lightning:v24.02.2
stop_signal: SIGKILL
environment:
EXPOSE_TCP: "true"
LIGHTNINGD_CHAIN: "btc"
LIGHTNINGD_NETWORK: "regtest"
LIGHTNINGD_OPT: |
developer
bitcoin-datadir=/etc/bitcoin
bitcoin-rpcconnect=bitcoind
announce-addr=merchant_lightningd:9735

View File

@ -149,7 +149,7 @@ services:
- "bitcoin_datadir:/data"
customer_lightningd:
image: btcpayserver/lightning:v23.08-dev
image: btcpayserver/lightning:v24.02.2
stop_signal: SIGKILL
restart: unless-stopped
environment:
@ -157,6 +157,7 @@ services:
LIGHTNINGD_CHAIN: "btc"
LIGHTNINGD_NETWORK: "regtest"
LIGHTNINGD_OPT: |
developer
bitcoin-datadir=/etc/bitcoin
bitcoin-rpcconnect=bitcoind
announce-addr=customer_lightningd:9735
@ -176,13 +177,14 @@ services:
- bitcoind
merchant_lightningd:
image: btcpayserver/lightning:v23.08-dev
image: btcpayserver/lightning:v24.02.2
stop_signal: SIGKILL
environment:
EXPOSE_TCP: "true"
LIGHTNINGD_CHAIN: "btc"
LIGHTNINGD_NETWORK: "regtest"
LIGHTNINGD_OPT: |
developer
bitcoin-datadir=/etc/bitcoin
bitcoin-rpcconnect=bitcoind
announce-addr=merchant_lightningd:9735

View File

@ -50,7 +50,7 @@
<PackageReference Include="YamlDotNet" Version="8.0.0" />
<PackageReference Include="BIP78.Sender" Version="0.2.2" />
<PackageReference Include="BTCPayServer.Hwi" Version="2.0.2" />
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.5.4" />
<PackageReference Include="BTCPayServer.Lightning.All" Version="1.6.0" />
<PackageReference Include="CsvHelper" Version="15.0.5" />
<PackageReference Include="Dapper" Version="2.1.28" />
<PackageReference Include="Fido2" Version="2.0.2" />

View File

@ -277,6 +277,10 @@ namespace BTCPayServer.Controllers
if (FormDataService.Validate(form, ModelState))
{
prBlob.FormResponse = FormDataService.GetValues(form);
if(string.IsNullOrEmpty(prBlob.Email) && form.GetFieldByFullName("buyerEmail") is { } emailField)
{
prBlob.Email = emailField.Value;
}
result.SetBlob(prBlob);
await _PaymentRequestRepository.CreateOrUpdatePaymentRequest(result);
return RedirectToAction("PayPaymentRequest", new { payReqId });

View File

@ -10,10 +10,9 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Models;
using BTCPayServer.Models.WalletViewModels;
using BTCPayServer.Payments;
using BTCPayServer.Rating;
using BTCPayServer.PayoutProcessors;
using BTCPayServer.Services;
using BTCPayServer.Services.Rates;
using Microsoft.AspNetCore.Authorization;
@ -23,7 +22,6 @@ using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
using MarkPayoutRequest = BTCPayServer.HostedServices.MarkPayoutRequest;
using PayoutData = BTCPayServer.Data.PayoutData;
using PullPaymentData = BTCPayServer.Data.PullPaymentData;
using StoreData = BTCPayServer.Data.StoreData;
namespace BTCPayServer.Controllers
@ -40,6 +38,8 @@ namespace BTCPayServer.Controllers
private readonly ApplicationDbContextFactory _dbContextFactory;
private readonly BTCPayNetworkJsonSerializerSettings _jsonSerializerSettings;
private readonly IAuthorizationService _authorizationService;
private readonly PayoutProcessorService _payoutProcessorService;
private readonly IEnumerable<IPayoutProcessorFactory> _payoutProcessorFactories;
public StoreData CurrentStore
{
@ -55,6 +55,8 @@ namespace BTCPayServer.Controllers
DisplayFormatter displayFormatter,
PullPaymentHostedService pullPaymentHostedService,
ApplicationDbContextFactory dbContextFactory,
PayoutProcessorService payoutProcessorService,
IEnumerable<IPayoutProcessorFactory> payoutProcessorFactories,
BTCPayNetworkJsonSerializerSettings jsonSerializerSettings,
IAuthorizationService authorizationService)
{
@ -66,8 +68,10 @@ namespace BTCPayServer.Controllers
_dbContextFactory = dbContextFactory;
_jsonSerializerSettings = jsonSerializerSettings;
_authorizationService = authorizationService;
_payoutProcessorService = payoutProcessorService;
_payoutProcessorFactories = payoutProcessorFactories;
}
[HttpGet("stores/{storeId}/pull-payments/new")]
[Authorize(Policy = Policies.CanCreateNonApprovedPullPayments, AuthenticationSchemes = AuthenticationSchemes.Cookie)]
public async Task<IActionResult> NewPullPayment(string storeId)
@ -287,6 +291,7 @@ namespace BTCPayServer.Controllers
return NotFound();
vm.PaymentMethods = await _payoutHandlers.GetSupportedPaymentMethods(HttpContext.GetStoreData());
vm.HasPayoutProcessor = await HasPayoutProcessor(storeId, vm.PaymentMethodId);
var paymentMethodId = PaymentMethodId.Parse(vm.PaymentMethodId);
var handler = _payoutHandlers
.FindPayoutHandler(paymentMethodId);
@ -370,7 +375,7 @@ namespace BTCPayServer.Controllers
break;
}
if (command == "approve-pay")
if (command == "approve-pay" && !vm.HasPayoutProcessor)
{
goto case "pay";
}
@ -486,16 +491,18 @@ namespace BTCPayServer.Controllers
return RedirectToAction(nameof(UIStoresController.Index), "UIStores", new { storeId });
}
paymentMethodId ??= paymentMethods.First().ToString();
var vm = this.ParseListQuery(new PayoutsModel
{
PaymentMethods = paymentMethods,
PaymentMethodId = paymentMethodId ?? paymentMethods.First().ToString(),
PaymentMethodId = paymentMethodId,
PullPaymentId = pullPaymentId,
PayoutState = payoutState,
Skip = skip,
Count = count
Count = count,
Payouts = new List<PayoutsModel.PayoutModel>(),
HasPayoutProcessor = await HasPayoutProcessor(storeId, paymentMethodId)
});
vm.Payouts = new List<PayoutsModel.PayoutModel>();
await using var ctx = _dbContextFactory.CreateContext();
var payoutRequest =
ctx.Payouts.Where(p => p.StoreDataId == storeId && (p.PullPaymentDataId == null || !p.PullPaymentData.Archived));
@ -577,5 +584,13 @@ namespace BTCPayServer.Controllers
}
return View(vm);
}
private async Task<bool> HasPayoutProcessor(string storeId, string paymentMethodId)
{
var pmId = PaymentMethodId.Parse(paymentMethodId);
var processors = await _payoutProcessorService.GetProcessors(
new PayoutProcessorService.PayoutProcessorQuery { Stores = [storeId], PaymentMethods = [paymentMethodId] });
return _payoutProcessorFactories.Any(factory => factory.GetSupportedPaymentMethods().Contains(pmId)) && processors.Any();
}
}
}

View File

@ -19,6 +19,7 @@ namespace BTCPayServer.Models.WalletViewModels
public IEnumerable<PaymentMethodId> PaymentMethods { get; set; }
public PayoutState PayoutState { get; set; }
public string PullPaymentName { get; set; }
public bool HasPayoutProcessor { get; set; }
public class PayoutModel
{

View File

@ -3,10 +3,10 @@ using Newtonsoft.Json;
namespace BTCPayServer.Services.Altcoins.Monero.RPC.Models
{
public partial class SyncInfoResponse
public partial class GetInfoResponse
{
[JsonProperty("height")] public long Height { get; set; }
[JsonProperty("peers")] public List<Peer> Peers { get; set; }
[JsonProperty("busy_syncing")] public bool BusySyncing { get; set; }
[JsonProperty("status")] public string Status { get; set; }
[JsonProperty("target_height")] public long? TargetHeight { get; set; }
}

View File

@ -59,12 +59,12 @@ namespace BTCPayServer.Services.Altcoins.Monero.Services
try
{
var daemonResult =
await daemonRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, SyncInfoResponse>("sync_info",
await daemonRpcClient.SendCommandAsync<JsonRpcClient.NoRequestModel, GetInfoResponse>("get_info",
JsonRpcClient.NoRequestModel.Instance);
summary.TargetHeight = daemonResult.TargetHeight.GetValueOrDefault(0);
summary.CurrentHeight = daemonResult.Height;
summary.TargetHeight = summary.TargetHeight == 0 ? summary.CurrentHeight : summary.TargetHeight;
summary.Synced = daemonResult.Height >= summary.TargetHeight && summary.CurrentHeight > 0;
summary.Synced = !daemonResult.BusySyncing;
summary.UpdatedAt = DateTime.UtcNow;
summary.DaemonAvailable = true;
}

View File

@ -104,14 +104,19 @@ namespace BTCPayServer.Services.Altcoins.Monero.UI
new SelectListItem(
$"{account.AccountIndex} - {(string.IsNullOrEmpty(account.Label) ? "No label" : account.Label)}",
account.AccountIndex.ToString(CultureInfo.InvariantCulture)));
var settlementThresholdChoice = settings.InvoiceSettledConfirmationThreshold switch
var settlementThresholdChoice = MoneroLikeSettlementThresholdChoice.StoreSpeedPolicy;
if (settings != null && settings.InvoiceSettledConfirmationThreshold is { } confirmations)
{
null => MoneroLikeSettlementThresholdChoice.StoreSpeedPolicy,
0 => MoneroLikeSettlementThresholdChoice.ZeroConfirmation,
1 => MoneroLikeSettlementThresholdChoice.AtLeastOne,
10 => MoneroLikeSettlementThresholdChoice.AtLeastTen,
_ => MoneroLikeSettlementThresholdChoice.Custom
};
settlementThresholdChoice = confirmations switch
{
0 => MoneroLikeSettlementThresholdChoice.ZeroConfirmation,
1 => MoneroLikeSettlementThresholdChoice.AtLeastOne,
10 => MoneroLikeSettlementThresholdChoice.AtLeastTen,
_ => MoneroLikeSettlementThresholdChoice.Custom
};
}
return new MoneroLikePaymentMethodViewModel()
{
WalletFileFound = System.IO.File.Exists(fileAddress),
@ -124,9 +129,11 @@ namespace BTCPayServer.Services.Altcoins.Monero.UI
Accounts = accounts == null ? null : new SelectList(accounts, nameof(SelectListItem.Value),
nameof(SelectListItem.Text)),
SettlementConfirmationThresholdChoice = settlementThresholdChoice,
CustomSettlementConfirmationThreshold = settlementThresholdChoice is MoneroLikeSettlementThresholdChoice.Custom
? settings.InvoiceSettledConfirmationThreshold
: null
CustomSettlementConfirmationThreshold =
settings != null &&
settlementThresholdChoice is MoneroLikeSettlementThresholdChoice.Custom
? settings.InvoiceSettledConfirmationThreshold
: null
};
}

File diff suppressed because one or more lines are too long

View File

@ -118,7 +118,10 @@
</p>
<dl class="mt-n1 mb-4" v-if="srvModel.amountCollected > 0 && srvModel.amountDue > 0">
<div class="progress bg-light d-flex mb-3 d-print-none" style="height:5px">
<div class="progress-bar bg-primary" role="progressbar" style="width:@(Model.AmountCollected/Model.Amount*100)%" v-bind:style="{ width: (srvModel.amountCollected/srvModel.amount*100) + '%' }"></div>
@{
var prcnt = Model.Amount == 0? 100: Model.AmountCollected / Model.Amount * 100;
}
<div class="progress-bar bg-primary" role="progressbar" style="width:@prcnt%" v-bind:style="{ width: (srvModel.amountCollected/srvModel.amount*100) + '%' }"></div>
</div>
<div class="d-flex flex-wrap gap-3 align-items-center justify-content-between">
<div class="d-flex d-print-inline-block flex-column gap-1">

View File

@ -7,8 +7,6 @@
@model BTCPayServer.Models.WalletViewModels.PayoutsModel
@inject IEnumerable<IPayoutHandler> PayoutHandlers;
@inject PayoutProcessorService _payoutProcessorService;
@inject IEnumerable<IPayoutProcessorFactory> _payoutProcessorFactories;
@{
var storeId = Context.GetRouteValue("storeId") as string;
ViewData.SetActivePage(StoreNavPages.Payouts, $"Payouts{(string.IsNullOrEmpty(Model.PullPaymentName) ? string.Empty : " for pull payment " + Model.PullPaymentName)}", Context.GetStoreData().Id);
@ -24,15 +22,16 @@
return;
stateActions.AddRange(payoutHandler.GetPayoutSpecificActions().Where(pair => pair.Key == Model.PayoutState).SelectMany(pair => pair.Value));
}
switch (Model.PayoutState)
{
case PayoutState.AwaitingApproval:
if (!Model.HasPayoutProcessor) stateActions.Add(("approve-pay", "Approve & Send"));
stateActions.Add(("approve", "Approve"));
stateActions.Add(("approve-pay", "Approve & Send"));
stateActions.Add(("cancel", "Cancel"));
break;
case PayoutState.AwaitingPayment:
stateActions.Add(("pay", "Send"));
if (!Model.HasPayoutProcessor) stateActions.Add(("pay", "Send"));
stateActions.Add(("cancel", "Cancel"));
stateActions.Add(("mark-paid", "Mark as already paid"));
break;
@ -87,11 +86,7 @@
<partial name="_StatusMessage" />
@if (_payoutProcessorFactories.Any(factory => factory.GetSupportedPaymentMethods().Contains(paymentMethodId)) && !(await _payoutProcessorService.GetProcessors(new PayoutProcessorService.PayoutProcessorQuery()
{
Stores = new[] { storeId },
PaymentMethods = new[] { Model.PaymentMethodId }
})).Any())
@if (!Model.HasPayoutProcessor)
{
<div class="alert alert-info mb-5" role="alert" permission="@Policies.CanModifyStoreSettings">
<strong>Pro tip:</strong> There are supported but unconfigured Payout Processors for this payout payment method.<br/>

View File

@ -1 +1,12 @@
<svg width="150" height="100" style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision" version="1.1" id="svg587" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><style id="style324">.st2{fill:#ffc214}.st3{fill:#f9f185}.st0{fill:#222221}.st1{fill:#272425}</style><g id="g931" transform="matrix(.375 0 0 .375 -306.863 -123.51)"><path fill-rule="evenodd" clip-rule="evenodd" d="M911.118 436.635c-7.865-3.02-11.793-11.842-8.774-19.707s11.842-11.793 19.707-8.774l56.773 21.793c.062.026.126.05.19.074l28.48 10.932c7.864 3.02 16.689-.909 19.706-8.774 3.02-7.865-.908-16.688-8.774-19.707v-.003l-28.48-10.932c-7.865-3.02-11.793-11.842-8.774-19.707 3.02-7.865 11.842-11.793 19.707-8.774l83.768 32.155c.2.077.399.158.594.242a84 84 0 0 1 1.08.406c39.325 15.095 58.967 59.21 43.87 98.535-15.095 39.324-59.21 58.965-98.534 43.87a78.402 78.402 0 0 1-2.249-.903c-.36-.11-.72-.232-1.076-.37l-82.117-31.521c-7.865-3.02-11.793-11.842-8.774-19.707s11.842-11.793 19.707-8.774l28.477 10.931-.002-.007.006.002c7.865 3.02 16.688-.909 19.706-8.774 3.02-7.865-.908-16.688-8.773-19.707l-12.817-4.92v-.001z" fill="currentColor" id="path1" style="clip-rule:evenodd;fill:#000;fill-rule:evenodd;stroke-width:1.52532;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"/></g></svg>
<svg width="150" height="100" style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision" version="1.1" id="svg587" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="#ffffff"/>
<style id="style324">
.st2{fill:#ffc214}
.st3{fill:#f9f185}
.st0{fill:#222221}
.st1{fill:#272425}
</style>
<g id="g931" transform="matrix(.375 0 0 .375 -306.863 -123.51)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M911.118 436.635c-7.865-3.02-11.793-11.842-8.774-19.707s11.842-11.793 19.707-8.774l56.773 21.793c.062.026.126.05.19.074l28.48 10.932c7.864 3.02 16.689-.909 19.706-8.774 3.02-7.865-.908-16.688-8.774-19.707v-.003l-28.48-10.932c-7.865-3.02-11.793-11.842-8.774-19.707 3.02-7.865 11.842-11.793 19.707-8.774l83.768 32.155c.2.077.399.158.594.242a84 84 0 0 1 1.08.406c39.325 15.095 58.967 59.21 43.87 98.535-15.095 39.324-59.21 58.965-98.534 43.87a78.402 78.402 0 0 1-2.249-.903c-.36-.11-.72-.232-1.076-.37l-82.117-31.521c-7.865-3.02-11.793-11.842-8.774-19.707s11.842-11.793 19.707-8.774l28.477 10.931-.002-.007.006.002c7.865 3.02 16.688-.909 19.706-8.774 3.02-7.865-.908-16.688-8.773-19.707l-12.817-4.92v-.001z" fill="currentColor" id="path1" style="clip-rule:evenodd;fill:#000;fill-rule:evenodd;stroke-width:1.52532;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="150" height="100" viewBox="0 0 150 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.4825 0.862305H88.0496C89.5663 0.862305 90.9675 1.64827 91.7239 2.92338L110.244 34.1419C111.204 35.7609 110.919 37.8043 109.549 39.1171L58.5729 87.9703C56.9216 89.5528 54.2652 89.5528 52.6139 87.9703L1.70699 39.1831C0.305262 37.8398 0.0427812 35.7367 1.07354 34.1077L20.8696 2.82322C21.6406 1.60483 23.0087 0.862305 24.4825 0.862305ZM79.8419 14.8003V23.5597H61.7343V29.6329C74.4518 30.2819 83.9934 32.9475 84.0642 36.1425L84.0638 42.803C83.993 45.998 74.4518 48.6635 61.7343 49.3125V64.2168H49.7105V49.3125C36.9929 48.6635 27.4513 45.998 27.3805 42.803L27.381 36.1425C27.4517 32.9475 36.9929 30.2819 49.7105 29.6329V23.5597H31.6028V14.8003H79.8419ZM55.7224 44.7367C69.2943 44.7367 80.6382 42.4827 83.4143 39.4727C81.0601 36.9202 72.5448 34.9114 61.7343 34.3597V40.7183C59.7966 40.8172 57.7852 40.8693 55.7224 40.8693C53.6595 40.8693 51.6481 40.8172 49.7105 40.7183V34.3597C38.8999 34.9114 30.3846 36.9202 28.0304 39.4727C30.8066 42.4827 42.1504 44.7367 55.7224 44.7367Z" fill="#009393" transform="translate(20, 5)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -185,7 +185,7 @@ function downloadCSV() {
// Convert ISO8601 dates to YYYY-MM-DD HH:mm:ss so the CSV easily integrate with Excel
modifyFields(srv.result.fields, data, 'amount', displayValue)
modifyFields(srv.result.fields, data, 'datetime', v => v? moment(v).format('YYYY-MM-DD hh:mm:ss'): v);
modifyFields(srv.result.fields, data, 'datetime', v => v ? moment(v).format('YYYY-MM-DD HH:mm:ss') : v);
const csv = Papa.unparse({ fields: srv.result.fields.map(f => f.name), data });
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
saveAs(blob, "export.csv");

View File

@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<Version>1.13.0</Version>
<Version>1.13.1</Version>
</PropertyGroup>
</Project>

View File

@ -1,5 +1,19 @@
# Changelog
## 1.13.1
### Bug fixes
* Fix: CSV exports from the Reports were exporting dates in 12-hour format instead of 24-hour format. (#5915, #5922) @TChukwuleta
* Fix: Crash when configuring BTCPay Server with a non-default Postgres schema (Fix #5901) @NicolasDorier
* Fix: A payment request with an amount of 0 no longer causes the payment request's page to crash (#5926) @Kukks
### Improvements
* Prevent unintentional double payouts (#5931, #5913) @dennisreimann
* The `buyerEmail` field in a Payment Request's form will now set the email for the payment request (#5926) @Kukks
* Added Tether as a supporter to the BTCPay Server Foundation (#5891) @rockstardev
## 1.13.0
### New feature

View File

@ -213,13 +213,15 @@ BTCPay Server software, logo and designs are provided under [MIT License](https:
The BTCPay Server Project is proudly supported by these entities through the [BTCPay Server Foundation](https://foundation.btcpayserver.org/).
[![Spiral](BTCPayServer/wwwroot/img/readme/supporter_spiral.svg)](https://spiral.xyz)
[![Baillie Gifford](BTCPayServer/wwwroot/img/readme/supporter_bailliegifford.svg)](https://www.bailliegifford.com)
[![Strike](BTCPayServer/wwwroot/img/readme/supporter_strike.svg)](https://strike.me)
[![Human Rights Foundation](BTCPayServer/wwwroot/img/readme/supporter_hrf.svg)](https://hrf.org)
[![LunaNode](BTCPayServer/wwwroot/img/readme/supporter_lunanode.svg)](https://lunanode.com)
[![Wallet of Satoshi](BTCPayServer/wwwroot/img/readme/supporter_walletofsatoshi.svg)](https://walletofsatoshi.com/)
[![Coincards](BTCPayServer/wwwroot/img/readme/supporter_coincards.svg)](https://coincards.com/)
[![IVPN](BTCPayServer/wwwroot/img/readme/supporter_ivpn.svg)](https://ivpn.net/)
[![Spiral](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_spiral.svg)](https://spiral.xyz)
[![OpenSats](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_opensats.svg)](https://opensats.org)
[![Baillie Gifford](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_bailliegifford.svg)](https://www.bailliegifford.com)
[![Tether](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_tether.svg)](https://tether.to)
[![Human Rights Foundation](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_hrf.svg)](https://hrf.org)
[![Strike](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_strike.svg)](https://strike.me)
[![LunaNode](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_lunanode.svg)](https://lunanode.com)
[![Wallet of Satoshi](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_walletofsatoshi.svg)](https://walletofsatoshi.com/)
[![Coincards](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_coincards.svg)](https://coincards.com/)
[![IVPN](https://raw.githubusercontent.com/btcpayserver/btcpayserver/master/BTCPayServer/wwwroot/img/readme/supporter_ivpn.svg)](https://ivpn.net/)
If you'd like to support the project, please visit the [donation page](https://btcpayserver.org/donate/).