Rename invoice states and payment states

This commit is contained in:
nicolas.dorier
2020-11-23 15:57:05 +09:00
parent f3010f622c
commit 18e68d04f9
30 changed files with 179 additions and 159 deletions

View File

@@ -59,7 +59,7 @@ namespace BTCPayServer.Client
{ {
if (request == null) if (request == null)
throw new ArgumentNullException(nameof(request)); throw new ArgumentNullException(nameof(request));
if (request.Status!= InvoiceStatus.Complete && request.Status!= InvoiceStatus.Invalid) if (request.Status!= InvoiceStatus.Settled && request.Status!= InvoiceStatus.Invalid)
throw new ArgumentOutOfRangeException(nameof(request.Status), "Status can only be Invalid or Complete"); throw new ArgumentOutOfRangeException(nameof(request.Status), "Status can only be Invalid or Complete");
var response = await _httpClient.SendAsync( var response = await _httpClient.SendAsync(
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/status", bodyPayload: request, CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/status", bodyPayload: request,

View File

@@ -18,4 +18,12 @@ namespace BTCPayServer.Client.Models
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))] [JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
public DateTimeOffset CreatedTime { get; set; } public DateTimeOffset CreatedTime { get; set; }
} }
public enum InvoiceStatus
{
New,
Processing,
Expired,
Invalid,
Settled
}
} }

View File

@@ -53,8 +53,8 @@ namespace BTCPayServer.Client.Models
public enum PaymentStatus public enum PaymentStatus
{ {
Invalid, Invalid,
AwaitingCompletion, Processing,
Complete Settled
} }
} }
} }

View File

@@ -1,12 +0,0 @@
namespace BTCPayServer.Client.Models
{
public enum InvoiceStatus
{
New,
Paid,
Expired,
Invalid,
Complete,
Confirmed
}
}

View File

@@ -8,9 +8,9 @@ namespace BTCPayServer.Client.Models
{ {
InvoiceCreated, InvoiceCreated,
InvoiceReceivedPayment, InvoiceReceivedPayment,
InvoicePaidInFull, InvoiceProcessing,
InvoiceExpired, InvoiceExpired,
InvoiceConfirmed, InvoiceSettled,
InvoiceInvalid InvoiceInvalid
} }
} }

View File

@@ -22,13 +22,13 @@ namespace BTCPayServer.Client.Models
public string InvoiceId { get; set; } public string InvoiceId { get; set; }
} }
public class WebhookInvoiceConfirmedEvent : WebhookInvoiceEvent public class WebhookInvoiceSettledEvent : WebhookInvoiceEvent
{ {
public WebhookInvoiceConfirmedEvent() public WebhookInvoiceSettledEvent()
{ {
} }
public WebhookInvoiceConfirmedEvent(WebhookEventType evtType) : base(evtType) public WebhookInvoiceSettledEvent(WebhookEventType evtType) : base(evtType)
{ {
} }
@@ -46,18 +46,17 @@ namespace BTCPayServer.Client.Models
public bool ManuallyMarked { get; set; } public bool ManuallyMarked { get; set; }
} }
public class WebhookInvoicePaidEvent : WebhookInvoiceEvent public class WebhookInvoiceProcessingEvent : WebhookInvoiceEvent
{ {
public WebhookInvoicePaidEvent() public WebhookInvoiceProcessingEvent()
{ {
} }
public WebhookInvoicePaidEvent(WebhookEventType evtType) : base(evtType) public WebhookInvoiceProcessingEvent(WebhookEventType evtType) : base(evtType)
{ {
} }
public bool OverPaid { get; set; } public bool OverPaid { get; set; }
public bool PaidAfterExpiration { get; set; }
} }
public class WebhookInvoiceReceivedPaymentEvent : WebhookInvoiceEvent public class WebhookInvoiceReceivedPaymentEvent : WebhookInvoiceEvent
{ {

View File

@@ -949,10 +949,10 @@ namespace BTCPayServer.Tests
var invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id); var invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id);
Assert.Equal(newInvoice.Metadata, invoice.Metadata); Assert.Equal(newInvoice.Metadata, invoice.Metadata);
var paymentMethods = await viewOnly.GetInvoicePaymentMethods(user.StoreId, newInvoice.Id); var paymentMethods = await viewOnly.GetInvoicePaymentMethods(user.StoreId, newInvoice.Id);
Assert.Equal(1, paymentMethods.Length); Assert.Single(paymentMethods);
var paymentMethod = paymentMethods.First(); var paymentMethod = paymentMethods.First();
Assert.Equal("BTC", paymentMethod.PaymentMethod); Assert.Equal("BTC", paymentMethod.PaymentMethod);
Assert.Equal(0, paymentMethod.Payments.Count); Assert.Empty(paymentMethod.Payments);
//update //update
@@ -962,7 +962,7 @@ namespace BTCPayServer.Tests
{ {
await client.MarkInvoiceStatus(user.StoreId, invoice.Id, new MarkInvoiceStatusRequest() await client.MarkInvoiceStatus(user.StoreId, invoice.Id, new MarkInvoiceStatusRequest()
{ {
Status = InvoiceStatus.Complete Status = InvoiceStatus.Settled
}); });
}); });
@@ -982,7 +982,7 @@ namespace BTCPayServer.Tests
Assert.NotNull(await client.GetInvoice(user.StoreId, invoice.Id)); Assert.NotNull(await client.GetInvoice(user.StoreId, invoice.Id));
foreach (var marked in new[] { InvoiceStatus.Complete, InvoiceStatus.Invalid }) foreach (var marked in new[] { InvoiceStatus.Settled, InvoiceStatus.Invalid })
{ {
var inv = await client.CreateInvoice(user.StoreId, var inv = await client.CreateInvoice(user.StoreId,
new CreateInvoiceRequest() { Currency = "USD", Amount = 100 }); new CreateInvoiceRequest() { Currency = "USD", Amount = 100 });
@@ -992,10 +992,10 @@ namespace BTCPayServer.Tests
Status = marked Status = marked
}); });
var result = await client.GetInvoice(user.StoreId, inv.Id); var result = await client.GetInvoice(user.StoreId, inv.Id);
if (marked == InvoiceStatus.Complete) if (marked == InvoiceStatus.Settled)
{ {
Assert.Equal(InvoiceStatus.Complete, result.Status); Assert.Equal(InvoiceStatus.Settled, result.Status);
user.AssertHasWebhookEvent<WebhookInvoiceConfirmedEvent>(WebhookEventType.InvoiceConfirmed, user.AssertHasWebhookEvent<WebhookInvoiceSettledEvent>(WebhookEventType.InvoiceSettled,
o => o =>
{ {
Assert.Equal(inv.Id, o.InvoiceId); Assert.Equal(inv.Id, o.InvoiceId);

View File

@@ -270,7 +270,7 @@ namespace BTCPayServer.Tests
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>
{ {
var invoice = await s.Server.PayTester.GetService<InvoiceRepository>().GetInvoice(invoiceId); var invoice = await s.Server.PayTester.GetService<InvoiceRepository>().GetInvoice(invoiceId);
Assert.Equal(InvoiceStatus.Paid, invoice.Status); Assert.Equal(InvoiceStatusLegacy.Paid, invoice.Status);
}); });
s.GoToInvoices(); s.GoToInvoices();
@@ -330,7 +330,7 @@ namespace BTCPayServer.Tests
{ {
var invoice = await s.Server.PayTester.GetService<InvoiceRepository>().GetInvoice(invoiceId); var invoice = await s.Server.PayTester.GetService<InvoiceRepository>().GetInvoice(invoiceId);
var dto = invoice.EntityToDTO(); var dto = invoice.EntityToDTO();
Assert.Equal(InvoiceStatus.Paid, invoice.Status); Assert.Equal(InvoiceStatusLegacy.Paid, invoice.Status);
}); });
s.GoToInvoices(); s.GoToInvoices();
paymentValueRowColumn = s.Driver.FindElement(By.Id($"invoice_{invoiceId}")) paymentValueRowColumn = s.Driver.FindElement(By.Id($"invoice_{invoiceId}"))
@@ -720,7 +720,7 @@ retry:
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>
{ {
var invoice = await tester.PayTester.GetService<InvoiceRepository>().GetInvoice(lastInvoiceId); var invoice = await tester.PayTester.GetService<InvoiceRepository>().GetInvoice(lastInvoiceId);
Assert.Equal(InvoiceStatus.Paid, invoice.Status); Assert.Equal(InvoiceStatusLegacy.Paid, invoice.Status);
Assert.Equal(InvoiceExceptionStatus.None, invoice.ExceptionStatus); Assert.Equal(InvoiceExceptionStatus.None, invoice.ExceptionStatus);
var coins = await btcPayWallet.GetUnspentCoins(receiverUser.DerivationScheme); var coins = await btcPayWallet.GetUnspentCoins(receiverUser.DerivationScheme);
foreach (var coin in coins) foreach (var coin in coins)
@@ -1047,7 +1047,7 @@ retry:
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>
{ {
var invoiceEntity = await tester.PayTester.GetService<InvoiceRepository>().GetInvoice(invoice7.Id); var invoiceEntity = await tester.PayTester.GetService<InvoiceRepository>().GetInvoice(invoice7.Id);
Assert.Equal(InvoiceStatus.Paid, invoiceEntity.Status); Assert.Equal(InvoiceStatusLegacy.Paid, invoiceEntity.Status);
Assert.Contains(invoiceEntity.GetPayments(), p => p.Accounted && Assert.Contains(invoiceEntity.GetPayments(), p => p.Accounted &&
((BitcoinLikePaymentData)p.GetCryptoPaymentData()).PayjoinInformation is null); ((BitcoinLikePaymentData)p.GetCryptoPaymentData()).PayjoinInformation is null);
}); });
@@ -1076,7 +1076,7 @@ retry:
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>
{ {
var invoiceEntity = await tester.PayTester.GetService<InvoiceRepository>().GetInvoice(invoice7.Id); var invoiceEntity = await tester.PayTester.GetService<InvoiceRepository>().GetInvoice(invoice7.Id);
Assert.Equal(InvoiceStatus.New, invoiceEntity.Status); Assert.Equal(InvoiceStatusLegacy.New, invoiceEntity.Status);
Assert.True(invoiceEntity.GetPayments().All(p => !p.Accounted)); Assert.True(invoiceEntity.GetPayments().All(p => !p.Accounted));
ourOutpoint = invoiceEntity.GetAllBitcoinPaymentData().First().PayjoinInformation.ContributedOutPoints[0]; ourOutpoint = invoiceEntity.GetAllBitcoinPaymentData().First().PayjoinInformation.ContributedOutPoints[0];
}); });

View File

@@ -207,12 +207,12 @@ namespace BTCPayServer.Tests
pair => pair.Key == "Id" && pair.Value.ToString() == invoiceId); pair => pair.Key == "Id" && pair.Value.ToString() == invoiceId);
var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); var invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant);
Assert.Equal(InvoiceState.ToString(InvoiceStatus.New), invoice.Status); Assert.Equal(InvoiceState.ToString(InvoiceStatusLegacy.New), invoice.Status);
Assert.IsType<OkObjectResult>(await Assert.IsType<OkObjectResult>(await
paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false)); paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false));
invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant); invoice = user.BitPay.GetInvoice(invoiceId, Facade.Merchant);
Assert.Equal(InvoiceState.ToString(InvoiceStatus.Invalid), invoice.Status); Assert.Equal(InvoiceState.ToString(InvoiceStatusLegacy.Invalid), invoice.Status);
Assert.IsType<BadRequestObjectResult>(await Assert.IsType<BadRequestObjectResult>(await
paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false)); paymentRequestController.CancelUnpaidPendingInvoice(paymentRequestId, false));

View File

@@ -624,7 +624,7 @@ namespace BTCPayServer.Tests
new SelectElement(s.Driver.FindElement(By.Name("Everything"))) new SelectElement(s.Driver.FindElement(By.Name("Everything")))
.SelectByValue("false"); .SelectByValue("false");
s.Driver.FindElement(By.Id("InvoiceCreated")).Click(); s.Driver.FindElement(By.Id("InvoiceCreated")).Click();
s.Driver.FindElement(By.Id("InvoicePaidInFull")).Click(); s.Driver.FindElement(By.Id("InvoiceProcessing")).Click();
s.Driver.FindElement(By.Name("add")).Click(); s.Driver.FindElement(By.Name("add")).Click();
} }
@@ -657,7 +657,7 @@ namespace BTCPayServer.Tests
Assert.Contains($"value=\"{value}\"", s.Driver.PageSource); Assert.Contains($"value=\"{value}\"", s.Driver.PageSource);
} }
// This one should be checked // This one should be checked
Assert.Contains($"value=\"InvoicePaidInFull\" checked", s.Driver.PageSource); Assert.Contains($"value=\"InvoiceProcessing\" checked", s.Driver.PageSource);
Assert.Contains($"value=\"InvoiceCreated\" checked", s.Driver.PageSource); Assert.Contains($"value=\"InvoiceCreated\" checked", s.Driver.PageSource);
// This one never been checked // This one never been checked
Assert.DoesNotContain($"value=\"InvoiceReceivedPayment\" checked", s.Driver.PageSource); Assert.DoesNotContain($"value=\"InvoiceReceivedPayment\" checked", s.Driver.PageSource);

View File

@@ -785,7 +785,7 @@ namespace BTCPayServer.Tests
}, evt => evt.InvoiceId == invoice.Id); }, evt => evt.InvoiceId == invoice.Id);
var fetchedInvoice = await tester.PayTester.InvoiceRepository.GetInvoice(evt.InvoiceId); var fetchedInvoice = await tester.PayTester.InvoiceRepository.GetInvoice(evt.InvoiceId);
Assert.Contains(fetchedInvoice.Status, new[] { InvoiceStatus.Complete, InvoiceStatus.Confirmed }); Assert.Contains(fetchedInvoice.Status, new[] { InvoiceStatusLegacy.Complete, InvoiceStatusLegacy.Confirmed });
Assert.Equal(InvoiceExceptionStatus.None, fetchedInvoice.ExceptionStatus); Assert.Equal(InvoiceExceptionStatus.None, fetchedInvoice.ExceptionStatus);
Logs.Tester.LogInformation($"Paying invoice {invoice.Id} original full amount bolt11 invoice "); Logs.Tester.LogInformation($"Paying invoice {invoice.Id} original full amount bolt11 invoice ");
@@ -1090,7 +1090,7 @@ namespace BTCPayServer.Tests
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
AssertConnectionDropped(); AssertConnectionDropped();
Logs.Tester.LogInformation("Querying an onion address which can't be found should send http 500"); Logs.Tester.LogInformation("Querying an onin address which can't be found should send http 500");
response = await client.GetAsync("http://dwoduwoi.onion/"); response = await client.GetAsync("http://dwoduwoi.onion/");
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
AssertConnectionDropped(); AssertConnectionDropped();
@@ -1460,7 +1460,7 @@ namespace BTCPayServer.Tests
await TestUtils.EventuallyAsync(async () => await TestUtils.EventuallyAsync(async () =>
{ {
var i = await tester.PayTester.InvoiceRepository.GetInvoice(invoice2.Id); var i = await tester.PayTester.InvoiceRepository.GetInvoice(invoice2.Id);
Assert.Equal(InvoiceStatus.New, i.Status); Assert.Equal(InvoiceStatusLegacy.New, i.Status);
Assert.Single(i.GetPayments()); Assert.Single(i.GetPayments());
Assert.False(i.GetPayments().First().Accounted); Assert.False(i.GetPayments().First().Accounted);
}); });
@@ -2743,12 +2743,12 @@ namespace BTCPayServer.Tests
}); });
// Test on the webhooks // Test on the webhooks
user.AssertHasWebhookEvent<WebhookInvoiceConfirmedEvent>(WebhookEventType.InvoiceConfirmed, user.AssertHasWebhookEvent<WebhookInvoiceSettledEvent>(WebhookEventType.InvoiceSettled,
c => c =>
{ {
Assert.False(c.ManuallyMarked); Assert.False(c.ManuallyMarked);
}); });
user.AssertHasWebhookEvent<WebhookInvoicePaidEvent>(WebhookEventType.InvoicePaidInFull, user.AssertHasWebhookEvent<WebhookInvoiceProcessingEvent>(WebhookEventType.InvoiceProcessing,
c => c =>
{ {
Assert.True(c.OverPaid); Assert.True(c.OverPaid);

View File

@@ -268,8 +268,8 @@ namespace BTCPayServer.Controllers.GreenField
? InvoicePaymentMethodDataModel.Payment.PaymentStatus.Invalid ? InvoicePaymentMethodDataModel.Payment.PaymentStatus.Invalid
: data.PaymentConfirmed(paymentEntity, entity.SpeedPolicy) || : data.PaymentConfirmed(paymentEntity, entity.SpeedPolicy) ||
data.PaymentCompleted(paymentEntity) data.PaymentCompleted(paymentEntity)
? InvoicePaymentMethodDataModel.Payment.PaymentStatus.Complete ? InvoicePaymentMethodDataModel.Payment.PaymentStatus.Settled
: InvoicePaymentMethodDataModel.Payment.PaymentStatus.AwaitingCompletion, : InvoicePaymentMethodDataModel.Payment.PaymentStatus.Processing,
Fee = paymentEntity.NetworkFee, Fee = paymentEntity.NetworkFee,
Value = data.GetValue(), Value = data.GetValue(),
ReceivedDate = paymentEntity.ReceivedTime.DateTime ReceivedDate = paymentEntity.ReceivedTime.DateTime
@@ -287,7 +287,7 @@ namespace BTCPayServer.Controllers.GreenField
CreatedTime = entity.InvoiceTime, CreatedTime = entity.InvoiceTime,
Amount = entity.Price, Amount = entity.Price,
Id = entity.Id, Id = entity.Id,
Status = entity.Status, Status = entity.Status.ToModernStatus(),
AdditionalStatus = entity.ExceptionStatus, AdditionalStatus = entity.ExceptionStatus,
Currency = entity.Currency, Currency = entity.Currency,
Metadata = entity.Metadata.ToJObject(), Metadata = entity.Metadata.ToJObject(),

View File

@@ -150,13 +150,13 @@ namespace BTCPayServer.Controllers
bool CanRefund(InvoiceState invoiceState) bool CanRefund(InvoiceState invoiceState)
{ {
return invoiceState.Status == InvoiceStatus.Confirmed || return invoiceState.Status == InvoiceStatusLegacy.Confirmed ||
invoiceState.Status == InvoiceStatus.Complete || invoiceState.Status == InvoiceStatusLegacy.Complete ||
(invoiceState.Status == InvoiceStatus.Expired && (invoiceState.Status == InvoiceStatusLegacy.Expired &&
(invoiceState.ExceptionStatus == InvoiceExceptionStatus.PaidLate || (invoiceState.ExceptionStatus == InvoiceExceptionStatus.PaidLate ||
invoiceState.ExceptionStatus == InvoiceExceptionStatus.PaidOver || invoiceState.ExceptionStatus == InvoiceExceptionStatus.PaidOver ||
invoiceState.ExceptionStatus == InvoiceExceptionStatus.PaidPartial)) || invoiceState.ExceptionStatus == InvoiceExceptionStatus.PaidPartial)) ||
invoiceState.Status == InvoiceStatus.Invalid; invoiceState.Status == InvoiceStatusLegacy.Invalid;
} }
[HttpGet] [HttpGet]
@@ -638,7 +638,7 @@ namespace BTCPayServer.Controllers
if (!HttpContext.WebSockets.IsWebSocketRequest) if (!HttpContext.WebSockets.IsWebSocketRequest)
return NotFound(); return NotFound();
var invoice = await _InvoiceRepository.GetInvoice(invoiceId); var invoice = await _InvoiceRepository.GetInvoice(invoiceId);
if (invoice == null || invoice.Status == InvoiceStatus.Complete || invoice.Status == InvoiceStatus.Invalid || invoice.Status == InvoiceStatus.Expired) if (invoice == null || invoice.Status == InvoiceStatusLegacy.Complete || invoice.Status == InvoiceStatusLegacy.Invalid || invoice.Status == InvoiceStatusLegacy.Expired)
return NotFound(); return NotFound();
var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(); var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
CompositeDisposable leases = new CompositeDisposable(); CompositeDisposable leases = new CompositeDisposable();
@@ -715,7 +715,7 @@ namespace BTCPayServer.Controllers
model.Invoices.Add(new InvoiceModel() model.Invoices.Add(new InvoiceModel()
{ {
Status = state, Status = state,
ShowCheckout = invoice.Status == InvoiceStatus.New, ShowCheckout = invoice.Status == InvoiceStatusLegacy.New,
Date = invoice.InvoiceTime, Date = invoice.InvoiceTime,
InvoiceId = invoice.Id, InvoiceId = invoice.Id,
OrderId = invoice.Metadata.OrderId ?? string.Empty, OrderId = invoice.Metadata.OrderId ?? string.Empty,
@@ -873,7 +873,7 @@ namespace BTCPayServer.Controllers
} }
else if (newState == "complete") else if (newState == "complete")
{ {
await _InvoiceRepository.MarkInvoiceStatus(invoiceId, InvoiceStatus.Complete); await _InvoiceRepository.MarkInvoiceStatus(invoiceId, InvoiceStatus.Settled);
model.StatusString = new InvoiceState("complete", "marked").ToString(); model.StatusString = new InvoiceState("complete", "marked").ToString();
} }

View File

@@ -200,7 +200,7 @@ namespace BTCPayServer.Controllers
throw new BitpayHttpException(400, "Invalid email"); throw new BitpayHttpException(400, "Invalid email");
entity.RefundMail = entity.Metadata.BuyerEmail; entity.RefundMail = entity.Metadata.BuyerEmail;
} }
entity.Status = InvoiceStatus.New; entity.Status = InvoiceStatusLegacy.New;
HashSet<CurrencyPair> currencyPairsToFetch = new HashSet<CurrencyPair>(); HashSet<CurrencyPair> currencyPairsToFetch = new HashSet<CurrencyPair>();
var rules = storeBlob.GetRateRules(_NetworkProvider); var rules = storeBlob.GetRateRules(_NetworkProvider);
var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any() var excludeFilter = storeBlob.GetExcludedPaymentMethods(); // Here we can compose filters from other origin with PaymentFilter.Any()

View File

@@ -238,8 +238,8 @@ namespace BTCPayServer.Controllers
var stateAllowedToDisplay = new HashSet<InvoiceState>() var stateAllowedToDisplay = new HashSet<InvoiceState>()
{ {
new InvoiceState(InvoiceStatus.New, InvoiceExceptionStatus.None), new InvoiceState(InvoiceStatusLegacy.New, InvoiceExceptionStatus.None),
new InvoiceState(InvoiceStatus.New, InvoiceExceptionStatus.PaidPartial), new InvoiceState(InvoiceStatusLegacy.New, InvoiceExceptionStatus.PaidPartial),
}; };
var currentInvoice = result var currentInvoice = result
.Invoices .Invoices
@@ -303,7 +303,7 @@ namespace BTCPayServer.Controllers
} }
var invoices = result.Invoices.Where(requestInvoice => var invoices = result.Invoices.Where(requestInvoice =>
requestInvoice.State.Status == InvoiceStatus.New && !requestInvoice.Payments.Any()); requestInvoice.State.Status == InvoiceStatusLegacy.New && !requestInvoice.Payments.Any());
if (!invoices.Any()) if (!invoices.Any())
{ {

View File

@@ -86,7 +86,7 @@ namespace BTCPayServer.Controllers
.ToArray(); .ToArray();
var firstInvoiceStillPending = var firstInvoiceStillPending =
matchedExistingInvoices.FirstOrDefault(entity => entity.GetInvoiceState().Status == InvoiceStatus.New); matchedExistingInvoices.FirstOrDefault(entity => entity.GetInvoiceState().Status == InvoiceStatusLegacy.New);
if (firstInvoiceStillPending != null) if (firstInvoiceStillPending != null)
{ {
return Ok(new return Ok(new
@@ -98,7 +98,7 @@ namespace BTCPayServer.Controllers
var firstInvoiceSettled = var firstInvoiceSettled =
matchedExistingInvoices.LastOrDefault(entity => matchedExistingInvoices.LastOrDefault(entity =>
new[] {InvoiceStatus.Paid, InvoiceStatus.Complete, InvoiceStatus.Confirmed}.Contains( new[] {InvoiceStatusLegacy.Paid, InvoiceStatusLegacy.Complete, InvoiceStatusLegacy.Confirmed}.Contains(
entity.GetInvoiceState().Status)); entity.GetInvoiceState().Status));
var store = await _Repo.FindStore(storeId); var store = await _Repo.FindStore(storeId);
@@ -119,7 +119,7 @@ namespace BTCPayServer.Controllers
{ {
//if BTCPay was shut down before the tx managed to get registered on shopify, this will fix it on the next UI load in shopify //if BTCPay was shut down before the tx managed to get registered on shopify, this will fix it on the next UI load in shopify
if (client != null && order?.FinancialStatus == "pending" && if (client != null && order?.FinancialStatus == "pending" &&
firstInvoiceSettled.Status != InvoiceStatus.Paid) firstInvoiceSettled.Status != InvoiceStatusLegacy.Paid)
{ {
await new OrderTransactionRegisterLogic(client).Process(orderId, firstInvoiceSettled.Id, await new OrderTransactionRegisterLogic(client).Process(orderId, firstInvoiceSettled.Id,
firstInvoiceSettled.Currency, firstInvoiceSettled.Currency,

View File

@@ -99,11 +99,11 @@ namespace BTCPayServer.HostedServices
// So here, we just override the status expressed by the notification // So here, we just override the status expressed by the notification
if (invoiceEvent.Name == InvoiceEvent.Confirmed) if (invoiceEvent.Name == InvoiceEvent.Confirmed)
{ {
notification.Data.Status = InvoiceState.ToString(InvoiceStatus.Confirmed); notification.Data.Status = InvoiceState.ToString(InvoiceStatusLegacy.Confirmed);
} }
if (invoiceEvent.Name == InvoiceEvent.PaidInFull) if (invoiceEvent.Name == InvoiceEvent.PaidInFull)
{ {
notification.Data.Status = InvoiceState.ToString(InvoiceStatus.Paid); notification.Data.Status = InvoiceState.ToString(InvoiceStatusLegacy.Paid);
} }
////////////////// //////////////////

View File

@@ -68,11 +68,11 @@ namespace BTCPayServer.HostedServices
private void UpdateInvoice(UpdateInvoiceContext context) private void UpdateInvoice(UpdateInvoiceContext context)
{ {
var invoice = context.Invoice; var invoice = context.Invoice;
if (invoice.Status == InvoiceStatus.New && invoice.ExpirationTime <= DateTimeOffset.UtcNow) if (invoice.Status == InvoiceStatusLegacy.New && invoice.ExpirationTime <= DateTimeOffset.UtcNow)
{ {
context.MarkDirty(); context.MarkDirty();
context.UnaffectAddresses(); context.UnaffectAddresses();
invoice.Status = InvoiceStatus.Expired; invoice.Status = InvoiceStatusLegacy.Expired;
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.Expired)); context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.Expired));
if (invoice.ExceptionStatus == InvoiceExceptionStatus.PaidPartial) if (invoice.ExceptionStatus == InvoiceExceptionStatus.PaidPartial)
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.ExpiredPaidPartial)); context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.ExpiredPaidPartial));
@@ -81,19 +81,19 @@ namespace BTCPayServer.HostedServices
var paymentMethod = GetNearestClearedPayment(allPaymentMethods, out var accounting); var paymentMethod = GetNearestClearedPayment(allPaymentMethods, out var accounting);
if (paymentMethod == null) if (paymentMethod == null)
return; return;
if (invoice.Status == InvoiceStatus.New || invoice.Status == InvoiceStatus.Expired) if (invoice.Status == InvoiceStatusLegacy.New || invoice.Status == InvoiceStatusLegacy.Expired)
{ {
if (accounting.Paid >= accounting.MinimumTotalDue) if (accounting.Paid >= accounting.MinimumTotalDue)
{ {
if (invoice.Status == InvoiceStatus.New) if (invoice.Status == InvoiceStatusLegacy.New)
{ {
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.PaidInFull)); context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.PaidInFull));
invoice.Status = InvoiceStatus.Paid; invoice.Status = InvoiceStatusLegacy.Paid;
invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? InvoiceExceptionStatus.PaidOver : InvoiceExceptionStatus.None; invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? InvoiceExceptionStatus.PaidOver : InvoiceExceptionStatus.None;
context.UnaffectAddresses(); context.UnaffectAddresses();
context.MarkDirty(); context.MarkDirty();
} }
else if (invoice.Status == InvoiceStatus.Expired && invoice.ExceptionStatus != InvoiceExceptionStatus.PaidLate) else if (invoice.Status == InvoiceStatusLegacy.Expired && invoice.ExceptionStatus != InvoiceExceptionStatus.PaidLate)
{ {
invoice.ExceptionStatus = InvoiceExceptionStatus.PaidLate; invoice.ExceptionStatus = InvoiceExceptionStatus.PaidLate;
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.PaidAfterExpiration)); context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.PaidAfterExpiration));
@@ -109,7 +109,7 @@ namespace BTCPayServer.HostedServices
} }
// Just make sure RBF did not cancelled a payment // Just make sure RBF did not cancelled a payment
if (invoice.Status == InvoiceStatus.Paid) if (invoice.Status == InvoiceStatusLegacy.Paid)
{ {
if (accounting.MinimumTotalDue <= accounting.Paid && accounting.Paid <= accounting.TotalDue && invoice.ExceptionStatus == InvoiceExceptionStatus.PaidOver) if (accounting.MinimumTotalDue <= accounting.Paid && accounting.Paid <= accounting.TotalDue && invoice.ExceptionStatus == InvoiceExceptionStatus.PaidOver)
{ {
@@ -125,13 +125,13 @@ namespace BTCPayServer.HostedServices
if (accounting.Paid < accounting.MinimumTotalDue) if (accounting.Paid < accounting.MinimumTotalDue)
{ {
invoice.Status = InvoiceStatus.New; invoice.Status = InvoiceStatusLegacy.New;
invoice.ExceptionStatus = accounting.Paid == Money.Zero ? InvoiceExceptionStatus.None : InvoiceExceptionStatus.PaidPartial; invoice.ExceptionStatus = accounting.Paid == Money.Zero ? InvoiceExceptionStatus.None : InvoiceExceptionStatus.PaidPartial;
context.MarkDirty(); context.MarkDirty();
} }
} }
if (invoice.Status == InvoiceStatus.Paid) if (invoice.Status == InvoiceStatusLegacy.Paid)
{ {
var confirmedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentConfirmed(p, invoice.SpeedPolicy)); var confirmedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentConfirmed(p, invoice.SpeedPolicy));
@@ -143,25 +143,25 @@ namespace BTCPayServer.HostedServices
{ {
context.UnaffectAddresses(); context.UnaffectAddresses();
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.FailedToConfirm)); context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.FailedToConfirm));
invoice.Status = InvoiceStatus.Invalid; invoice.Status = InvoiceStatusLegacy.Invalid;
context.MarkDirty(); context.MarkDirty();
} }
else if (confirmedAccounting.Paid >= accounting.MinimumTotalDue) else if (confirmedAccounting.Paid >= accounting.MinimumTotalDue)
{ {
context.UnaffectAddresses(); context.UnaffectAddresses();
invoice.Status = InvoiceStatus.Confirmed; invoice.Status = InvoiceStatusLegacy.Confirmed;
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.Confirmed)); context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.Confirmed));
context.MarkDirty(); context.MarkDirty();
} }
} }
if (invoice.Status == InvoiceStatus.Confirmed) if (invoice.Status == InvoiceStatusLegacy.Confirmed)
{ {
var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p)); var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p));
if (completedAccounting.Paid >= accounting.MinimumTotalDue) if (completedAccounting.Paid >= accounting.MinimumTotalDue)
{ {
context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.Completed)); context.Events.Add(new InvoiceEvent(invoice, InvoiceEvent.Completed));
invoice.Status = InvoiceStatus.Complete; invoice.Status = InvoiceStatusLegacy.Complete;
context.MarkDirty(); context.MarkDirty();
} }
} }
@@ -299,8 +299,8 @@ namespace BTCPayServer.HostedServices
_EventAggregator.Publish(evt, evt.GetType()); _EventAggregator.Publish(evt, evt.GetType());
} }
if (invoice.Status == InvoiceStatus.Complete || if (invoice.Status == InvoiceStatusLegacy.Complete ||
((invoice.Status == InvoiceStatus.Invalid || invoice.Status == InvoiceStatus.Expired) && invoice.MonitoringExpiration < DateTimeOffset.UtcNow)) ((invoice.Status == InvoiceStatusLegacy.Invalid || invoice.Status == InvoiceStatusLegacy.Expired) && invoice.MonitoringExpiration < DateTimeOffset.UtcNow))
{ {
var extendInvoiceMonitoring = await UpdateConfirmationCount(invoice); var extendInvoiceMonitoring = await UpdateConfirmationCount(invoice);

View File

@@ -17,6 +17,7 @@ using BTCPayServer.Client.Models;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.Logging; using BTCPayServer.Logging;
using BTCPayServer.Services.Invoices;
using BTCPayServer.Services.Stores; using BTCPayServer.Services.Stores;
using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Operations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -163,10 +164,11 @@ namespace BTCPayServer.HostedServices
switch (eventCode) switch (eventCode)
{ {
case InvoiceEventCode.Completed: case InvoiceEventCode.Completed:
case InvoiceEventCode.PaidAfterExpiration:
return null; return null;
case InvoiceEventCode.Confirmed: case InvoiceEventCode.Confirmed:
case InvoiceEventCode.MarkedCompleted: case InvoiceEventCode.MarkedCompleted:
return new WebhookInvoiceConfirmedEvent(WebhookEventType.InvoiceConfirmed) return new WebhookInvoiceSettledEvent(WebhookEventType.InvoiceSettled)
{ {
ManuallyMarked = eventCode == InvoiceEventCode.MarkedCompleted ManuallyMarked = eventCode == InvoiceEventCode.MarkedCompleted
}; };
@@ -185,16 +187,14 @@ namespace BTCPayServer.HostedServices
ManuallyMarked = eventCode == InvoiceEventCode.MarkedInvalid ManuallyMarked = eventCode == InvoiceEventCode.MarkedInvalid
}; };
case InvoiceEventCode.PaidInFull: case InvoiceEventCode.PaidInFull:
case InvoiceEventCode.PaidAfterExpiration: return new WebhookInvoiceProcessingEvent(WebhookEventType.InvoiceProcessing)
return new WebhookInvoicePaidEvent(WebhookEventType.InvoicePaidInFull)
{ {
OverPaid = invoiceEvent.Invoice.ExceptionStatus == InvoiceExceptionStatus.PaidOver, OverPaid = invoiceEvent.Invoice.ExceptionStatus == InvoiceExceptionStatus.PaidOver,
PaidAfterExpiration = eventCode == InvoiceEventCode.PaidAfterExpiration
}; };
case InvoiceEventCode.ReceivedPayment: case InvoiceEventCode.ReceivedPayment:
return new WebhookInvoiceReceivedPaymentEvent(WebhookEventType.InvoiceReceivedPayment) return new WebhookInvoiceReceivedPaymentEvent(WebhookEventType.InvoiceReceivedPayment)
{ {
AfterExpiration = invoiceEvent.Invoice.Status == InvoiceStatus.Expired || invoiceEvent.Invoice.Status == InvoiceStatus.Invalid AfterExpiration = invoiceEvent.Invoice.Status.ToModernStatus() == InvoiceStatus.Expired || invoiceEvent.Invoice.Status.ToModernStatus() == InvoiceStatus.Invalid
}; };
default: default:
return null; return null;

View File

@@ -142,7 +142,7 @@ namespace BTCPayServer.Models.PaymentRequestViewModels
public decimal Amount { get; set; } public decimal Amount { get; set; }
public string AmountFormatted { get; set; } public string AmountFormatted { get; set; }
public InvoiceState State { get; set; } public InvoiceState State { get; set; }
public InvoiceStatus Status { get; set; } public InvoiceStatusLegacy Status { get; set; }
public string StateFormatted { get; set; } public string StateFormatted { get; set; }
public List<PaymentRequestInvoicePayment> Payments { get; set; } public List<PaymentRequestInvoicePayment> Payments { get; set; }

View File

@@ -83,7 +83,7 @@ namespace BTCPayServer.PaymentRequest
var paymentStats = _AppService.GetContributionsByPaymentMethodId(blob.Currency, invoices, true); var paymentStats = _AppService.GetContributionsByPaymentMethodId(blob.Currency, invoices, true);
var amountDue = blob.Amount - paymentStats.TotalCurrency; var amountDue = blob.Amount - paymentStats.TotalCurrency;
var pendingInvoice = invoices.OrderByDescending(entity => entity.InvoiceTime) var pendingInvoice = invoices.OrderByDescending(entity => entity.InvoiceTime)
.FirstOrDefault(entity => entity.Status == InvoiceStatus.New); .FirstOrDefault(entity => entity.Status == InvoiceStatusLegacy.New);
return new ViewPaymentRequestViewModel(pr) return new ViewPaymentRequestViewModel(pr)
{ {

View File

@@ -144,7 +144,7 @@ namespace BTCPayServer.Payments.Lightning
_CheckInvoices.Writer.TryWrite(inv.Invoice.Id); _CheckInvoices.Writer.TryWrite(inv.Invoice.Id);
} }
if (inv.Name == InvoiceEvent.ReceivedPayment && inv.Invoice.Status == InvoiceStatus.New && inv.Invoice.ExceptionStatus == InvoiceExceptionStatus.PaidPartial) if (inv.Name == InvoiceEvent.ReceivedPayment && inv.Invoice.Status == InvoiceStatusLegacy.New && inv.Invoice.ExceptionStatus == InvoiceExceptionStatus.PaidPartial)
{ {
var pm = inv.Invoice.GetPaymentMethods().First(); var pm = inv.Invoice.GetPaymentMethods().First();
if (pm.Calculate().Due.GetValue(pm.Network as BTCPayNetwork) > 0m) if (pm.Calculate().Due.GetValue(pm.Network as BTCPayNetwork) > 0m)
@@ -155,7 +155,7 @@ namespace BTCPayServer.Payments.Lightning
})); }));
leases.Add(_Aggregator.Subscribe<Events.InvoiceDataChangedEvent>(async inv => leases.Add(_Aggregator.Subscribe<Events.InvoiceDataChangedEvent>(async inv =>
{ {
if (inv.State.Status == InvoiceStatus.New && if (inv.State.Status == InvoiceStatusLegacy.New &&
inv.State.ExceptionStatus == InvoiceExceptionStatus.PaidPartial) inv.State.ExceptionStatus == InvoiceExceptionStatus.PaidPartial)
{ {

View File

@@ -89,9 +89,9 @@ namespace BTCPayServer.Services.Apps
} }
var invoices = await GetInvoicesForApp(appData, lastResetDate); var invoices = await GetInvoicesForApp(appData, lastResetDate);
var completeInvoices = invoices.Where(entity => entity.Status == InvoiceStatus.Complete || entity.Status == InvoiceStatus.Confirmed).ToArray(); var completeInvoices = invoices.Where(entity => entity.Status == InvoiceStatusLegacy.Complete || entity.Status == InvoiceStatusLegacy.Confirmed).ToArray();
var pendingInvoices = invoices.Where(entity => !(entity.Status == InvoiceStatus.Complete || entity.Status == InvoiceStatus.Confirmed)).ToArray(); var pendingInvoices = invoices.Where(entity => !(entity.Status == InvoiceStatusLegacy.Complete || entity.Status == InvoiceStatusLegacy.Confirmed)).ToArray();
var paidInvoices = invoices.Where(entity => entity.Status == InvoiceStatus.Complete || entity.Status == InvoiceStatus.Confirmed || entity.Status == InvoiceStatus.Paid).ToArray(); var paidInvoices = invoices.Where(entity => entity.Status == InvoiceStatusLegacy.Complete || entity.Status == InvoiceStatusLegacy.Confirmed || entity.Status == InvoiceStatusLegacy.Paid).ToArray();
var pendingPayments = GetContributionsByPaymentMethodId(settings.TargetCurrency, pendingInvoices, !settings.EnforceTargetAmount); var pendingPayments = GetContributionsByPaymentMethodId(settings.TargetCurrency, pendingInvoices, !settings.EnforceTargetAmount);
var currentPayments = GetContributionsByPaymentMethodId(settings.TargetCurrency, completeInvoices, !settings.EnforceTargetAmount); var currentPayments = GetContributionsByPaymentMethodId(settings.TargetCurrency, completeInvoices, !settings.EnforceTargetAmount);
@@ -176,10 +176,10 @@ namespace BTCPayServer.Services.Apps
StoreId = new[] { appData.StoreData.Id }, StoreId = new[] { appData.StoreData.Id },
OrderId = appData.TagAllInvoices ? null : new[] { GetCrowdfundOrderId(appData.Id) }, OrderId = appData.TagAllInvoices ? null : new[] { GetCrowdfundOrderId(appData.Id) },
Status = new string[]{ Status = new string[]{
InvoiceState.ToString(InvoiceStatus.New), InvoiceState.ToString(InvoiceStatusLegacy.New),
InvoiceState.ToString(InvoiceStatus.Paid), InvoiceState.ToString(InvoiceStatusLegacy.Paid),
InvoiceState.ToString(InvoiceStatus.Confirmed), InvoiceState.ToString(InvoiceStatusLegacy.Confirmed),
InvoiceState.ToString(InvoiceStatus.Complete)}, InvoiceState.ToString(InvoiceStatusLegacy.Complete)},
StartDate = startDate StartDate = startDate
}); });
@@ -340,7 +340,7 @@ namespace BTCPayServer.Services.Apps
contribution.Value = contribution.CurrencyValue; contribution.Value = contribution.CurrencyValue;
// For hardcap, we count newly created invoices as part of the contributions // For hardcap, we count newly created invoices as part of the contributions
if (!softcap && p.Status == InvoiceStatus.New) if (!softcap && p.Status == InvoiceStatusLegacy.New)
return new[] { contribution }; return new[] { contribution };
// If the user get a donation via other mean, he can register an invoice manually for such amount // If the user get a donation via other mean, he can register an invoice manually for such amount
@@ -348,7 +348,7 @@ namespace BTCPayServer.Services.Apps
var payments = p.GetPayments(); var payments = p.GetPayments();
if (payments.Count == 0 && if (payments.Count == 0 &&
p.ExceptionStatus == InvoiceExceptionStatus.Marked && p.ExceptionStatus == InvoiceExceptionStatus.Marked &&
p.Status == InvoiceStatus.Complete) p.Status == InvoiceStatusLegacy.Complete)
return new[] { contribution }; return new[] { contribution };
contribution.CurrencyValue = 0m; contribution.CurrencyValue = 0m;
@@ -356,7 +356,7 @@ namespace BTCPayServer.Services.Apps
// If an invoice has been marked invalid, remove the contribution // If an invoice has been marked invalid, remove the contribution
if (p.ExceptionStatus == InvoiceExceptionStatus.Marked && if (p.ExceptionStatus == InvoiceExceptionStatus.Marked &&
p.Status == InvoiceStatus.Invalid) p.Status == InvoiceStatusLegacy.Invalid)
return new[] { contribution }; return new[] { contribution };

View File

@@ -219,7 +219,7 @@ namespace BTCPayServer.Services.Invoices
} }
[JsonIgnore] [JsonIgnore]
public InvoiceStatus Status { get; set; } public InvoiceStatusLegacy Status { get; set; }
[JsonProperty(PropertyName = "status")] [JsonProperty(PropertyName = "status")]
[Obsolete("Use Status instead")] [Obsolete("Use Status instead")]
public string StatusString => InvoiceState.ToString(Status); public string StatusString => InvoiceState.ToString(Status);
@@ -578,24 +578,54 @@ namespace BTCPayServer.Services.Invoices
} }
} }
public enum InvoiceStatusLegacy
{
New,
Paid,
Expired,
Invalid,
Complete,
Confirmed
}
public static class InvoiceStatusLegacyExtensions
{
public static InvoiceStatus ToModernStatus(this InvoiceStatusLegacy legacy)
{
switch (legacy)
{
case InvoiceStatusLegacy.Complete:
case InvoiceStatusLegacy.Confirmed:
return InvoiceStatus.Settled;
case InvoiceStatusLegacy.Expired:
return InvoiceStatus.Expired;
case InvoiceStatusLegacy.Invalid:
return InvoiceStatus.Invalid;
case InvoiceStatusLegacy.Paid:
return InvoiceStatus.Processing;
case InvoiceStatusLegacy.New:
return InvoiceStatus.New;
default:
throw new NotSupportedException();
}
}
}
public class InvoiceState public class InvoiceState
{ {
static readonly Dictionary<string, InvoiceStatus> _StringToInvoiceStatus; static readonly Dictionary<string, InvoiceStatusLegacy> _StringToInvoiceStatus;
static readonly Dictionary<InvoiceStatus, string> _InvoiceStatusToString; static readonly Dictionary<InvoiceStatusLegacy, string> _InvoiceStatusToString;
static readonly Dictionary<string, InvoiceExceptionStatus> _StringToExceptionStatus; static readonly Dictionary<string, InvoiceExceptionStatus> _StringToExceptionStatus;
static readonly Dictionary<InvoiceExceptionStatus, string> _ExceptionStatusToString; static readonly Dictionary<InvoiceExceptionStatus, string> _ExceptionStatusToString;
static InvoiceState() static InvoiceState()
{ {
_StringToInvoiceStatus = new Dictionary<string, InvoiceStatus>(); _StringToInvoiceStatus = new Dictionary<string, InvoiceStatusLegacy>();
_StringToInvoiceStatus.Add("paid", InvoiceStatus.Paid); _StringToInvoiceStatus.Add("paid", InvoiceStatusLegacy.Paid);
_StringToInvoiceStatus.Add("expired", InvoiceStatus.Expired); _StringToInvoiceStatus.Add("expired", InvoiceStatusLegacy.Expired);
_StringToInvoiceStatus.Add("invalid", InvoiceStatus.Invalid); _StringToInvoiceStatus.Add("invalid", InvoiceStatusLegacy.Invalid);
_StringToInvoiceStatus.Add("complete", InvoiceStatus.Complete); _StringToInvoiceStatus.Add("complete", InvoiceStatusLegacy.Complete);
_StringToInvoiceStatus.Add("new", InvoiceStatus.New); _StringToInvoiceStatus.Add("new", InvoiceStatusLegacy.New);
_StringToInvoiceStatus.Add("confirmed", InvoiceStatus.Confirmed); _StringToInvoiceStatus.Add("confirmed", InvoiceStatusLegacy.Confirmed);
_InvoiceStatusToString = _StringToInvoiceStatus.ToDictionary(kv => kv.Value, kv => kv.Key); _InvoiceStatusToString = _StringToInvoiceStatus.ToDictionary(kv => kv.Value, kv => kv.Key);
_StringToExceptionStatus = new Dictionary<string, InvoiceExceptionStatus>(); _StringToExceptionStatus = new Dictionary<string, InvoiceExceptionStatus>();
@@ -612,16 +642,16 @@ namespace BTCPayServer.Services.Invoices
Status = _StringToInvoiceStatus[status]; Status = _StringToInvoiceStatus[status];
ExceptionStatus = _StringToExceptionStatus[exceptionStatus ?? string.Empty]; ExceptionStatus = _StringToExceptionStatus[exceptionStatus ?? string.Empty];
} }
public InvoiceState(InvoiceStatus status, InvoiceExceptionStatus exceptionStatus) public InvoiceState(InvoiceStatusLegacy status, InvoiceExceptionStatus exceptionStatus)
{ {
Status = status; Status = status;
ExceptionStatus = exceptionStatus; ExceptionStatus = exceptionStatus;
} }
public InvoiceStatus Status { get; } public InvoiceStatusLegacy Status { get; }
public InvoiceExceptionStatus ExceptionStatus { get; } public InvoiceExceptionStatus ExceptionStatus { get; }
public static string ToString(InvoiceStatus status) public static string ToString(InvoiceStatusLegacy status)
{ {
return _InvoiceStatusToString[status]; return _InvoiceStatusToString[status];
} }
@@ -633,20 +663,20 @@ namespace BTCPayServer.Services.Invoices
public bool CanMarkComplete() public bool CanMarkComplete()
{ {
return (Status == InvoiceStatus.Paid) || return (Status == InvoiceStatusLegacy.Paid) ||
((Status == InvoiceStatus.New || Status == InvoiceStatus.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidPartial) || ((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidPartial) ||
((Status == InvoiceStatus.New || Status == InvoiceStatus.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidLate) || ((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidLate) ||
(Status != InvoiceStatus.Complete && ExceptionStatus == InvoiceExceptionStatus.Marked) || (Status != InvoiceStatusLegacy.Complete && ExceptionStatus == InvoiceExceptionStatus.Marked) ||
(Status == InvoiceStatus.Invalid); (Status == InvoiceStatusLegacy.Invalid);
} }
public bool CanMarkInvalid() public bool CanMarkInvalid()
{ {
return (Status == InvoiceStatus.Paid) || return (Status == InvoiceStatusLegacy.Paid) ||
(Status == InvoiceStatus.New) || (Status == InvoiceStatusLegacy.New) ||
((Status == InvoiceStatus.New || Status == InvoiceStatus.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidPartial) || ((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidPartial) ||
((Status == InvoiceStatus.New || Status == InvoiceStatus.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidLate) || ((Status == InvoiceStatusLegacy.New || Status == InvoiceStatusLegacy.Expired) && ExceptionStatus == InvoiceExceptionStatus.PaidLate) ||
(Status != InvoiceStatus.Invalid && ExceptionStatus == InvoiceExceptionStatus.Marked); (Status != InvoiceStatusLegacy.Invalid && ExceptionStatus == InvoiceExceptionStatus.Marked);
} }
public override int GetHashCode() public override int GetHashCode()

View File

@@ -453,15 +453,17 @@ retry:
context.Attach(invoiceData); context.Attach(invoiceData);
string eventName; string eventName;
string legacyStatus;
switch (status) switch (status)
{ {
case InvoiceStatus.Complete: case InvoiceStatus.Settled:
if (!invoiceData.GetInvoiceState().CanMarkComplete()) if (!invoiceData.GetInvoiceState().CanMarkComplete())
{ {
return false; return false;
} }
eventName = InvoiceEvent.MarkedCompleted; eventName = InvoiceEvent.MarkedCompleted;
legacyStatus = InvoiceStatusLegacy.Complete.ToString();
break; break;
case InvoiceStatus.Invalid: case InvoiceStatus.Invalid:
if (!invoiceData.GetInvoiceState().CanMarkInvalid()) if (!invoiceData.GetInvoiceState().CanMarkInvalid())
@@ -469,12 +471,13 @@ retry:
return false; return false;
} }
eventName = InvoiceEvent.MarkedInvalid; eventName = InvoiceEvent.MarkedInvalid;
legacyStatus = InvoiceStatusLegacy.Invalid.ToString();
break; break;
default: default:
return false; return false;
} }
invoiceData.Status = status.ToString().ToLowerInvariant(); invoiceData.Status = legacyStatus.ToLowerInvariant();
invoiceData.ExceptionStatus = InvoiceExceptionStatus.Marked.ToString().ToLowerInvariant(); invoiceData.ExceptionStatus = InvoiceExceptionStatus.Marked.ToString().ToLowerInvariant();
_eventAggregator.Publish(new InvoiceEvent(ToEntity(invoiceData), eventName)); _eventAggregator.Publish(new InvoiceEvent(ToEntity(invoiceData), eventName));
await context.SaveChangesAsync(); await context.SaveChangesAsync();

View File

@@ -49,14 +49,14 @@ namespace BTCPayServer.Services.Shopify
var shopifyOrderId = invoice.GetInternalTags(SHOPIFY_ORDER_ID_PREFIX).FirstOrDefault(); var shopifyOrderId = invoice.GetInternalTags(SHOPIFY_ORDER_ID_PREFIX).FirstOrDefault();
if (shopifyOrderId != null) if (shopifyOrderId != null)
{ {
if (new[] {InvoiceStatus.Invalid, InvoiceStatus.Expired}.Contains(invoice.GetInvoiceState() if (new[] {InvoiceStatusLegacy.Invalid, InvoiceStatusLegacy.Expired}.Contains(invoice.GetInvoiceState()
.Status) && invoice.ExceptionStatus != InvoiceExceptionStatus.None) .Status) && invoice.ExceptionStatus != InvoiceExceptionStatus.None)
{ {
//you have failed us, customer //you have failed us, customer
await RegisterTransaction(invoice, shopifyOrderId, false); await RegisterTransaction(invoice, shopifyOrderId, false);
} }
else if (new[] {InvoiceStatus.Complete, InvoiceStatus.Confirmed}.Contains( else if (new[] {InvoiceStatusLegacy.Complete, InvoiceStatusLegacy.Confirmed}.Contains(
invoice.Status)) invoice.Status))
{ {
await RegisterTransaction(invoice, shopifyOrderId, true); await RegisterTransaction(invoice, shopifyOrderId, true);

View File

@@ -11,11 +11,10 @@
string StatusTextClass(InvoiceState state) string StatusTextClass(InvoiceState state)
{ {
switch (state.Status) switch (state.Status.ToModernStatus())
{ {
case InvoiceStatus.Confirmed: case InvoiceStatus.Settled:
case InvoiceStatus.Complete: case InvoiceStatus.Processing:
case InvoiceStatus.Paid:
return "text-success"; return "text-success";
case InvoiceStatus.Expired: case InvoiceStatus.Expired:
switch (state.ExceptionStatus) switch (state.ExceptionStatus)

View File

@@ -55,9 +55,9 @@
{ {
("A new invoice has been created", WebhookEventType.InvoiceCreated), ("A new invoice has been created", WebhookEventType.InvoiceCreated),
("A new payment has been received", WebhookEventType.InvoiceReceivedPayment), ("A new payment has been received", WebhookEventType.InvoiceReceivedPayment),
("An invoice is fully paid", WebhookEventType.InvoicePaidInFull), ("An invoice is processing", WebhookEventType.InvoiceProcessing),
("An invoice has expired", WebhookEventType.InvoiceExpired), ("An invoice has expired", WebhookEventType.InvoiceExpired),
("An invoice has been confirmed", WebhookEventType.InvoiceConfirmed), ("An invoice has been settled", WebhookEventType.InvoiceSettled),
("An invoice became invalid", WebhookEventType.InvoiceInvalid) ("An invoice became invalid", WebhookEventType.InvoiceInvalid)
}) })
{ {

View File

@@ -521,19 +521,17 @@
"description": "", "description": "",
"x-enumNames": [ "x-enumNames": [
"New", "New",
"Paid", "Processing",
"Expired", "Expired",
"Invalid", "Invalid",
"Complete", "Settled"
"Confirmed"
], ],
"enum": [ "enum": [
"New", "New",
"Paid", "Processing",
"Expired", "Expired",
"Invalid", "Invalid",
"Complete", "Settled"
"Confirmed"
] ]
}, },
"InvoiceAdditionalStatus": { "InvoiceAdditionalStatus": {
@@ -778,13 +776,13 @@
"description": "", "description": "",
"x-enumNames": [ "x-enumNames": [
"Invalid", "Invalid",
"AwaitingCompletion", "Processing",
"Complete" "Settled"
], ],
"enum": [ "enum": [
"Invalid", "Invalid",
"AwaitingCompletion", "Processing",
"Complete" "Settled"
] ]
} }
} }

View File

@@ -579,7 +579,7 @@
}, },
"specificEvents": { "specificEvents": {
"type": "string", "type": "string",
"description": "If `everything` is false, the specific events that the endpoint is interested in. Current events are: `InvoiceCreated`, `InvoiceReceivedPayment`, `InvoicePaidInFull`, `InvoiceExpired`, `InvoiceConfirmed`, `InvoiceInvalid`.", "description": "If `everything` is false, the specific events that the endpoint is interested in. Current events are: `InvoiceCreated`, `InvoiceReceivedPayment`, `InvoiceProcessing`, `InvoiceExpired`, `InvoiceSettled`, `InvoiceInvalid`.",
"nullable": false "nullable": false
} }
} }
@@ -644,8 +644,8 @@
} }
] ]
}, },
"WebhookInvoiceConfirmedEvent": { "WebhookInvoiceSettledEvent": {
"description": "Callback sent if the `type` is `InvoiceConfirmed`", "description": "Callback sent if the `type` is `InvoiceSettled`",
"allOf": [ "allOf": [
{ {
"$ref": "#/components/schemas/WebhookInvoiceEvent" "$ref": "#/components/schemas/WebhookInvoiceEvent"
@@ -680,8 +680,8 @@
} }
] ]
}, },
"WebhookInvoicePaidEvent": { "WebhookInvoiceProcessingEvent": {
"description": "Callback sent if the `type` is `InvoicePaidInFull`", "description": "Callback sent if the `type` is `InvoiceProcessing`",
"allOf": [ "allOf": [
{ {
"$ref": "#/components/schemas/WebhookInvoiceEvent" "$ref": "#/components/schemas/WebhookInvoiceEvent"
@@ -693,11 +693,6 @@
"type": "boolean", "type": "boolean",
"description": "Whether this invoice has received more money than expected", "description": "Whether this invoice has received more money than expected",
"nullable": false "nullable": false
},
"paidAfterExpiration": {
"type": "boolean",
"description": "Whether this invoice has been paid too late",
"nullable": false
} }
} }
} }
@@ -832,9 +827,9 @@
} }
} }
}, },
"Invoice paid": { "Invoice processing": {
"post": { "post": {
"summary": "Invoice paid", "summary": "Invoice processing",
"description": "An invoice has been fully paid", "description": "An invoice has been fully paid",
"parameters": [ "parameters": [
{ {
@@ -855,7 +850,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/WebhookInvoicePaidEvent" "$ref": "#/components/schemas/WebhookInvoiceProcessingEvent"
} }
} }
} }
@@ -892,10 +887,10 @@
} }
} }
}, },
"Invoice confirmed": { "Invoice settled": {
"post": { "post": {
"summary": "Invoice confirmed", "summary": "Invoice settled",
"description": "An invoice has been confirmed, order considered settled", "description": "An invoice has been settled",
"parameters": [ "parameters": [
{ {
"in": "header", "in": "header",
@@ -915,7 +910,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/WebhookInvoiceConfirmedEvent" "$ref": "#/components/schemas/WebhookInvoiceSettledEvent"
} }
} }
} }