From b4cd74056e7a0fc1ddd16dacef418e02078a2d2e Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Wed, 1 May 2024 17:59:10 +0900 Subject: [PATCH] Remove period concept from PullPayment (#5963) --- .../Models/CreatePullPaymentRequest.cs | 2 - .../Models/PullPaymentBaseData.cs | 2 - BTCPayServer.Data/Data/PayoutData.cs | 12 ---- BTCPayServer.Data/Data/PullPaymentData.cs | 57 +++++-------------- .../Migrations/20240501015052_noperiod.cs | 31 ++++++++++ .../ApplicationDbContextModelSnapshot.cs | 3 - BTCPayServer.Tests/FastTests.cs | 37 ------------ BTCPayServer.Tests/GreenfieldAPITests.cs | 1 - .../GreenField/GreenfieldInvoiceController.cs | 1 - .../GreenfieldPullPaymentController.cs | 6 -- .../Controllers/UIPullPaymentController.cs | 2 +- .../Data/PullPayments/PullPaymentBlob.cs | 2 - .../PullPaymentHostedService.cs | 22 +++---- BTCPayServer/Models/ViewPullPaymentModel.cs | 18 +++--- .../WalletViewModels/PullPaymentsModel.cs | 1 - .../UIPullPayment/ViewPullPayment.cshtml | 6 +- .../UIStorePullPayments/PullPayments.cshtml | 5 -- .../v1/swagger.template.pull-payments.json | 13 ----- 18 files changed, 66 insertions(+), 155 deletions(-) create mode 100644 BTCPayServer.Data/Migrations/20240501015052_noperiod.cs diff --git a/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs b/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs index 7589df432..2d4a75306 100644 --- a/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs +++ b/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs @@ -12,8 +12,6 @@ namespace BTCPayServer.Client.Models [JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))] public decimal Amount { get; set; } public string Currency { get; set; } - [JsonConverter(typeof(TimeSpanJsonConverter.Seconds))] - public TimeSpan? Period { get; set; } [JsonConverter(typeof(TimeSpanJsonConverter.Days))] [JsonProperty("BOLT11Expiration")] public TimeSpan? BOLT11Expiration { get; set; } diff --git a/BTCPayServer.Client/Models/PullPaymentBaseData.cs b/BTCPayServer.Client/Models/PullPaymentBaseData.cs index 7bec49dcc..ef7fdbc0a 100644 --- a/BTCPayServer.Client/Models/PullPaymentBaseData.cs +++ b/BTCPayServer.Client/Models/PullPaymentBaseData.cs @@ -24,8 +24,6 @@ namespace BTCPayServer.Client.Models public string Currency { get; set; } [JsonConverter(typeof(NumericStringJsonConverter))] public decimal Amount { get; set; } - [JsonConverter(typeof(TimeSpanJsonConverter.Seconds))] - public TimeSpan? Period { get; set; } [JsonConverter(typeof(TimeSpanJsonConverter.Days))] [JsonProperty("BOLT11Expiration")] public TimeSpan BOLT11Expiration { get; set; } diff --git a/BTCPayServer.Data/Data/PayoutData.cs b/BTCPayServer.Data/Data/PayoutData.cs index c1cd5b87a..c79cc9109 100644 --- a/BTCPayServer.Data/Data/PayoutData.cs +++ b/BTCPayServer.Data/Data/PayoutData.cs @@ -54,17 +54,5 @@ namespace BTCPayServer.Data .Property(o => o.Proof) .HasColumnType("JSONB"); } - - // utility methods - public bool IsInPeriod(PullPaymentData pp, DateTimeOffset now) - { - var period = pp.GetPeriod(now); - if (period is { } p) - { - return p.Start <= Date && (p.End is not { } end || Date < end); - } - - return false; - } } } diff --git a/BTCPayServer.Data/Data/PullPaymentData.cs b/BTCPayServer.Data/Data/PullPaymentData.cs index 66abd7702..820be4924 100644 --- a/BTCPayServer.Data/Data/PullPaymentData.cs +++ b/BTCPayServer.Data/Data/PullPaymentData.cs @@ -4,11 +4,13 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; +using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Client.Models; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using NBitcoin; +using static System.Runtime.InteropServices.JavaScript.JSType; namespace BTCPayServer.Data { @@ -22,7 +24,6 @@ namespace BTCPayServer.Data public StoreData StoreData { get; set; } [MaxLength(50)] public string StoreId { get; set; } - public long? Period { get; set; } public DateTimeOffset StartDate { get; set; } public DateTimeOffset? EndDate { get; set; } public bool Archived { get; set; } @@ -49,27 +50,25 @@ namespace BTCPayServer.Data return null; if (EndDate is DateTimeOffset end && now >= end) return null; - DateTimeOffset startPeriod = StartDate; - DateTimeOffset? endPeriod = null; - if (Period is long periodSeconds) - { - var period = TimeSpan.FromSeconds(periodSeconds); - var timeToNow = now - StartDate; - var periodCount = (long)timeToNow.TotalSeconds / (long)period.TotalSeconds; - startPeriod = StartDate + (period * periodCount); - endPeriod = startPeriod + period; - } - if (EndDate is DateTimeOffset end2 && - ((endPeriod is null) || - (endPeriod is DateTimeOffset endP && endP > end2))) - endPeriod = end2; - return (startPeriod, endPeriod); + return (StartDate, EndDate); } public bool HasStarted() { return HasStarted(DateTimeOffset.UtcNow); } + public TimeSpan? EndsIn() => EndsIn(DateTimeOffset.UtcNow); + public TimeSpan? EndsIn(DateTimeOffset now) + { + if (EndDate is DateTimeOffset e) + { + var resetIn = (e - now); + if (resetIn < TimeSpan.Zero) + resetIn = TimeSpan.Zero; + return resetIn; + } + return null; + } public bool HasStarted(DateTimeOffset now) { return StartDate <= now; @@ -97,32 +96,6 @@ namespace BTCPayServer.Data public static class PayoutExtensions { - public static IQueryable GetPayoutInPeriod(this IQueryable payouts, PullPaymentData pp) - { - return GetPayoutInPeriod(payouts, pp, DateTimeOffset.UtcNow); - } - public static IQueryable GetPayoutInPeriod(this IQueryable payouts, PullPaymentData pp, DateTimeOffset now) - { - var request = payouts.Where(p => p.PullPaymentDataId == pp.Id); - var period = pp.GetPeriod(now); - if (period is { } p) - { - var start = p.Start; - if (p.End is DateTimeOffset end) - { - return request.Where(p => p.Date >= start && p.Date < end); - } - else - { - return request.Where(p => p.Date >= start); - } - } - else - { - return request.Where(p => false); - } - } - public static string GetStateString(this PayoutState state) { switch (state) diff --git a/BTCPayServer.Data/Migrations/20240501015052_noperiod.cs b/BTCPayServer.Data/Migrations/20240501015052_noperiod.cs new file mode 100644 index 000000000..8bc67c968 --- /dev/null +++ b/BTCPayServer.Data/Migrations/20240501015052_noperiod.cs @@ -0,0 +1,31 @@ +using BTCPayServer.Data; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BTCPayServer.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20240501015052_noperiod")] + public partial class noperiod : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Period", + table: "PullPayments"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Period", + table: "PullPayments", + type: "bigint", + nullable: true); + } + } +} diff --git a/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs b/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs index 9fda24494..e7a6d6c68 100644 --- a/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/BTCPayServer.Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -675,9 +675,6 @@ namespace BTCPayServer.Migrations b.Property("EndDate") .HasColumnType("timestamp with time zone"); - b.Property("Period") - .HasColumnType("bigint"); - b.Property("StartDate") .HasColumnType("timestamp with time zone"); diff --git a/BTCPayServer.Tests/FastTests.cs b/BTCPayServer.Tests/FastTests.cs index 4ee95fc44..58cc75cfe 100644 --- a/BTCPayServer.Tests/FastTests.cs +++ b/BTCPayServer.Tests/FastTests.cs @@ -717,43 +717,6 @@ namespace BTCPayServer.Tests Assert.Equal(0.0000_0001m, accounting.MinimumTotalDue); } - [Fact] - public void CanCalculatePeriod() - { - Data.PullPaymentData data = new Data.PullPaymentData(); - data.StartDate = Date(0); - data.EndDate = null; - var period = data.GetPeriod(Date(1)).Value; - Assert.Equal(Date(0), period.Start); - Assert.Null(period.End); - data.EndDate = Date(7); - period = data.GetPeriod(Date(1)).Value; - Assert.Equal(Date(0), period.Start); - Assert.Equal(Date(7), period.End); - data.Period = (long)TimeSpan.FromDays(2).TotalSeconds; - period = data.GetPeriod(Date(1)).Value; - Assert.Equal(Date(0), period.Start); - Assert.Equal(Date(2), period.End); - period = data.GetPeriod(Date(2)).Value; - Assert.Equal(Date(2), period.Start); - Assert.Equal(Date(4), period.End); - period = data.GetPeriod(Date(6)).Value; - Assert.Equal(Date(6), period.Start); - Assert.Equal(Date(7), period.End); - Assert.Null(data.GetPeriod(Date(7))); - Assert.Null(data.GetPeriod(Date(8))); - data.EndDate = null; - period = data.GetPeriod(Date(6)).Value; - Assert.Equal(Date(6), period.Start); - Assert.Equal(Date(8), period.End); - Assert.Null(data.GetPeriod(Date(-1))); - } - - private DateTimeOffset Date(int days) - { - return new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero) + TimeSpan.FromDays(days); - } - [Fact] public void CanDetectFileType() { diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 56ea238c4..081295de2 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -872,7 +872,6 @@ namespace BTCPayServer.Tests { Assert.Equal("Test", result.Name); Assert.Equal("Test description", result.Description); - Assert.Null(result.Period); // If it contains ? it means that we are resolving an unknown route with the link generator Assert.DoesNotContain("?", result.ViewLink); Assert.False(result.Archived); diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs index ffb645d92..491746a97 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldInvoiceController.cs @@ -567,7 +567,6 @@ namespace BTCPayServer.Controllers.Greenfield Name = ppBlob.Name, Description = ppBlob.Description, Currency = ppBlob.Currency, - Period = ppBlob.Period, Archived = pp.Archived, AutoApproveClaims = ppBlob.AutoApproveClaims, BOLT11Expiration = ppBlob.BOLT11Expiration, diff --git a/BTCPayServer/Controllers/GreenField/GreenfieldPullPaymentController.cs b/BTCPayServer/Controllers/GreenField/GreenfieldPullPaymentController.cs index b6f98828d..ff1081428 100644 --- a/BTCPayServer/Controllers/GreenField/GreenfieldPullPaymentController.cs +++ b/BTCPayServer/Controllers/GreenField/GreenfieldPullPaymentController.cs @@ -127,10 +127,6 @@ namespace BTCPayServer.Controllers.Greenfield { ModelState.AddModelError(nameof(request.ExpiresAt), $"expiresAt should be higher than startAt"); } - if (request.Period <= TimeSpan.Zero) - { - ModelState.AddModelError(nameof(request.Period), $"The period should be positive"); - } if (request.BOLT11Expiration < TimeSpan.Zero) { ModelState.AddModelError(nameof(request.BOLT11Expiration), $"The BOLT11 expiration should be positive"); @@ -162,7 +158,6 @@ namespace BTCPayServer.Controllers.Greenfield { StartsAt = request.StartsAt, ExpiresAt = request.ExpiresAt, - Period = request.Period, BOLT11Expiration = request.BOLT11Expiration, Name = request.Name, Description = request.Description, @@ -188,7 +183,6 @@ namespace BTCPayServer.Controllers.Greenfield Name = ppBlob.Name, Description = ppBlob.Description, Currency = ppBlob.Currency, - Period = ppBlob.Period, Archived = pp.Archived, AutoApproveClaims = ppBlob.AutoApproveClaims, BOLT11Expiration = ppBlob.BOLT11Expiration, diff --git a/BTCPayServer/Controllers/UIPullPaymentController.cs b/BTCPayServer/Controllers/UIPullPaymentController.cs index 72d26a75a..e69de073e 100644 --- a/BTCPayServer/Controllers/UIPullPaymentController.cs +++ b/BTCPayServer/Controllers/UIPullPaymentController.cs @@ -86,7 +86,7 @@ namespace BTCPayServer.Controllers return NotFound(); var storeBlob = store.GetStoreBlob(); - var payouts = (await ctx.Payouts.GetPayoutInPeriod(pp) + var payouts = (await ctx.Payouts.Where(p => p.PullPaymentDataId == pp.Id) .OrderByDescending(o => o.Date) .ToListAsync()) .Select(o => new diff --git a/BTCPayServer/Data/PullPayments/PullPaymentBlob.cs b/BTCPayServer/Data/PullPayments/PullPaymentBlob.cs index 84e293fb3..ed00997cd 100644 --- a/BTCPayServer/Data/PullPayments/PullPaymentBlob.cs +++ b/BTCPayServer/Data/PullPayments/PullPaymentBlob.cs @@ -19,8 +19,6 @@ namespace BTCPayServer.Data [JsonConverter(typeof(NumericStringJsonConverter))] public decimal MinimumClaim { get; set; } public PullPaymentView View { get; set; } = new PullPaymentView(); - [JsonConverter(typeof(TimeSpanJsonConverter.Seconds))] - public TimeSpan? Period { get; set; } [DefaultValue(typeof(TimeSpan), "30.00:00:00")] [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] diff --git a/BTCPayServer/HostedServices/PullPaymentHostedService.cs b/BTCPayServer/HostedServices/PullPaymentHostedService.cs index 4801032f8..9ec9e4755 100644 --- a/BTCPayServer/HostedServices/PullPaymentHostedService.cs +++ b/BTCPayServer/HostedServices/PullPaymentHostedService.cs @@ -41,7 +41,6 @@ namespace BTCPayServer.HostedServices public string CustomCSSLink { get; set; } public string EmbeddedCSS { get; set; } public PayoutMethodId[] PayoutMethodIds { get; set; } - public TimeSpan? Period { get; set; } public bool AutoApproveClaims { get; set; } public TimeSpan? BOLT11Expiration { get; set; } } @@ -121,7 +120,6 @@ namespace BTCPayServer.HostedServices ? date : DateTimeOffset.UtcNow - TimeSpan.FromSeconds(1.0); o.EndDate = create.ExpiresAt is DateTimeOffset date2 ? new DateTimeOffset?(date2) : null; - o.Period = create.Period is TimeSpan period ? (long?)period.TotalSeconds : null; o.Id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(20)); o.StoreId = create.StoreId; @@ -131,7 +129,6 @@ namespace BTCPayServer.HostedServices Description = create.Description ?? string.Empty, Currency = create.Currency, Limit = create.Amount, - Period = o.Period is long periodSeconds ? (TimeSpan?)TimeSpan.FromSeconds(periodSeconds) : null, SupportedPaymentMethods = create.PayoutMethodIds, AutoApproveClaims = create.AutoApproveClaims, View = new PullPaymentBlob.PullPaymentView() @@ -608,7 +605,7 @@ namespace BTCPayServer.HostedServices var payoutsRaw = withoutPullPayment ? null - : await ctx.Payouts.GetPayoutInPeriod(pp, now) + : await ctx.Payouts.Where(p => p.PullPaymentDataId == pp.Id) .Where(p => p.State != PayoutState.Cancelled).ToListAsync(); var payouts = payoutsRaw?.Select(o => new { Entity = o, Blob = o.GetBlob(_jsonSerializerSettings) }); @@ -801,15 +798,15 @@ namespace BTCPayServer.HostedServices var ni = _currencyNameTable.GetCurrencyData(ppBlob.Currency, true); var nfi = _currencyNameTable.GetNumberFormatInfo(ppBlob.Currency, true); - var totalCompleted = pp.Payouts.Where(p => (p.State == PayoutState.Completed || - p.State == PayoutState.InProgress) && p.IsInPeriod(pp, now)) + var totalCompleted = pp.Payouts + .Where(p => (p.State == PayoutState.Completed || + p.State == PayoutState.InProgress)) .Select(o => o.GetBlob(_jsonSerializerSettings).Amount).Sum().RoundToSignificant(ni.Divisibility); - var period = pp.GetPeriod(now); - var totalAwaiting = pp.Payouts.Where(p => (p.State == PayoutState.AwaitingPayment || - p.State == PayoutState.AwaitingApproval) && - p.IsInPeriod(pp, now)).Select(o => + var totalAwaiting = pp.Payouts + .Where(p => (p.State == PayoutState.AwaitingPayment || + p.State == PayoutState.AwaitingApproval)).Select(o => o.GetBlob(_jsonSerializerSettings).Amount).Sum().RoundToSignificant(ni.Divisibility); - ; + var currencyData = _currencyNameTable.GetCurrencyData(ppBlob.Currency, true); return new PullPaymentsModel.PullPaymentModel.ProgressModel() { @@ -821,8 +818,7 @@ namespace BTCPayServer.HostedServices CompletedFormatted = totalCompleted.ToString("C", nfi), Limit = ppBlob.Limit.RoundToSignificant(currencyData.Divisibility), LimitFormatted = _displayFormatter.Currency(ppBlob.Limit, ppBlob.Currency), - ResetIn = period?.End is { } nr ? ZeroIfNegative(nr - now).TimeString() : null, - EndIn = pp.EndDate is { } end ? ZeroIfNegative(end - now).TimeString() : null, + EndIn = pp.EndsIn() is { } end ? end.TimeString() : null, }; } diff --git a/BTCPayServer/Models/ViewPullPaymentModel.cs b/BTCPayServer/Models/ViewPullPaymentModel.cs index 458a9e465..07aa85ad3 100644 --- a/BTCPayServer/Models/ViewPullPaymentModel.cs +++ b/BTCPayServer/Models/ViewPullPaymentModel.cs @@ -35,17 +35,16 @@ namespace BTCPayServer.Models ExpiryDate = data.EndDate is DateTimeOffset dt ? (DateTime?)dt.UtcDateTime : null; Email = blob.View.Email; MinimumClaim = blob.MinimumClaim; - IsPending = !data.IsExpired(); - var period = data.GetPeriod(now); + IsPending = !data.IsExpired(now); if (data.Archived) { Status = "Archived"; } - else if (data.IsExpired()) + else if (data.IsExpired(now)) { Status = "Expired"; } - else if (period is null) + else if (!data.HasStarted(now)) { Status = "Not yet started"; } @@ -54,13 +53,10 @@ namespace BTCPayServer.Models Status = string.Empty; } - ResetIn = string.Empty; - if (period?.End is DateTimeOffset pe) + EndsIn = string.Empty; + if (data.EndsIn(now) is TimeSpan e) { - var resetIn = (pe - DateTimeOffset.UtcNow); - if (resetIn < TimeSpan.Zero) - resetIn = TimeSpan.Zero; - ResetIn = resetIn.TimeString(); + EndsIn = e.TimeString(); } } @@ -76,7 +72,7 @@ namespace BTCPayServer.Models public string ResetDeepLink { get; set; } public string HubPath { get; set; } - public string ResetIn { get; set; } + public string EndsIn { get; set; } public string Email { get; set; } public string Status { get; set; } public bool IsPending { get; set; } diff --git a/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs b/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs index 8e7472252..9671cb622 100644 --- a/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs +++ b/BTCPayServer/Models/WalletViewModels/PullPaymentsModel.cs @@ -20,7 +20,6 @@ namespace BTCPayServer.Models.WalletViewModels public string CompletedFormatted { get; set; } public string AwaitingFormatted { get; set; } public string LimitFormatted { get; set; } - public string ResetIn { get; set; } public string EndIn { get; set; } public decimal Awaiting { get; set; } public decimal Completed { get; set; } diff --git a/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml b/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml index d7c27892c..8cdb04143 100644 --- a/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml +++ b/BTCPayServer/Views/UIPullPayment/ViewPullPayment.cshtml @@ -111,12 +111,12 @@ Show QR - @if (!string.IsNullOrEmpty(Model.ResetIn)) + @if (!string.IsNullOrEmpty(Model.EndsIn)) {

- Reset in + Ends in   - @Model.ResetIn + @Model.EndsIn

} @if (!string.IsNullOrEmpty(Model.Description)) diff --git a/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml b/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml index 5bddc13fc..a462a4489 100644 --- a/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml +++ b/BTCPayServer/Views/UIStorePullPayments/PullPayments.cshtml @@ -87,11 +87,6 @@ Completed: @pp.Progress.CompletedFormatted
Limit: @pp.Progress.LimitFormatted - @if (pp.Progress.ResetIn != null) - { -
- Resets in: @pp.Progress.ResetIn - } @if (pp.Progress.EndIn != null) {
diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.pull-payments.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.pull-payments.json index 5d4e106c1..3b595aba7 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.pull-payments.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.pull-payments.json @@ -195,13 +195,6 @@ "example": "BTC", "description": "The currency of the amount." }, - "period": { - "type": "integer", - "format": "decimal", - "example": 604800, - "nullable": true, - "description": "The length of each period in seconds." - }, "BOLT11Expiration": { "type": "string", "example": 30, @@ -1179,12 +1172,6 @@ "example": "1.12000000", "description": "The amount in the currency of this pull payment as a decimal string" }, - "period": { - "type": "integer", - "example": 604800, - "nullable": true, - "description": "The length of each period in seconds" - }, "BOLT11Expiration": { "type": "string", "example": 30,