From 5076d7369556743c43b60dfc881755bb419691a4 Mon Sep 17 00:00:00 2001 From: Kukks Date: Sun, 6 Jan 2019 10:12:45 +0100 Subject: [PATCH] Enhance Invoice Events --- BTCPayServer.Tests/UnitTest1.cs | 11 ++++++----- .../Controllers/InvoiceController.UI.cs | 4 ++-- BTCPayServer/Controllers/InvoiceController.cs | 3 ++- BTCPayServer/Events/InvoiceEvent.cs | 14 ++++++++++++++ .../InvoiceNotificationManager.cs | 16 ++++++++-------- BTCPayServer/HostedServices/InvoiceWatcher.cs | 18 +++++++++--------- BTCPayServer/Models/InvoiceResponse.cs | 6 ++++++ .../Payments/Bitcoin/NBXplorerListener.cs | 2 +- .../Payments/Lightning/LightningListener.cs | 4 ++-- 9 files changed, 50 insertions(+), 28 deletions(-) diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 6c94c1115..5734380de 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -51,6 +51,7 @@ using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel; using NBitpayClient.Extensions; using BTCPayServer.Services; using System.Text.RegularExpressions; +using BTCPayServer.Events; namespace BTCPayServer.Tests { @@ -521,22 +522,22 @@ namespace BTCPayServer.Tests var evtName = request["event"]["name"].Value(); switch (evtName) { - case "invoice_created": + case InvoiceEvent.Created: tester.ExplorerNode.SendToAddress(url.Address, url.Amount); break; - case "invoice_receivedPayment": + case InvoiceEvent.ReceivedPayment: receivedPayment = true; break; - case "invoice_paidInFull": + case InvoiceEvent.PaidInFull: Assert.True(receivedPayment); tester.ExplorerNode.Generate(6); paid = true; break; - case "invoice_confirmed": + case InvoiceEvent.Confirmed: Assert.True(paid); confirmed = true; break; - case "invoice_completed": + case InvoiceEvent.Completed: Assert.True(paid); //TODO: Fix, out of order event mean we can receive invoice_confirmed after invoice_complete completed = true; break; diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index 74086aba6..4e9803d2d 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -638,13 +638,13 @@ namespace BTCPayServer.Controllers if (newState == "invalid") { await _InvoiceRepository.UpdatePaidInvoiceToInvalid(invoiceId); - _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1008, "invoice_markedInvalid")); + _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1008, InvoiceEvent.MarkedInvalid)); StatusMessage = "Invoice marked invalid"; } else if(newState == "complete") { await _InvoiceRepository.UpdatePaidInvoiceToComplete(invoiceId); - _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2008, "invoice_markedComplete")); + _EventAggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2008, InvoiceEvent.MarkedCompleted)); StatusMessage = "Invoice marked complete"; } return RedirectToAction(nameof(ListInvoices)); diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs index de58dc171..47c46a615 100644 --- a/BTCPayServer/Controllers/InvoiceController.cs +++ b/BTCPayServer/Controllers/InvoiceController.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using BTCPayServer.Data; +using BTCPayServer.Events; using BTCPayServer.Logging; using BTCPayServer.Models; using BTCPayServer.Payments; @@ -159,7 +160,7 @@ namespace BTCPayServer.Controllers entity.PosData = invoice.PosData; entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, logs, _NetworkProvider); await fetchingAll; - _EventAggregator.Publish(new Events.InvoiceEvent(entity.EntityToDTO(_NetworkProvider), 1001, "invoice_created")); + _EventAggregator.Publish(new Events.InvoiceEvent(entity.EntityToDTO(_NetworkProvider), 1001, InvoiceEvent.Created)); var resp = entity.EntityToDTO(_NetworkProvider); return new DataWrapper(resp) { Facade = "pos/invoice" }; } diff --git a/BTCPayServer/Events/InvoiceEvent.cs b/BTCPayServer/Events/InvoiceEvent.cs index c3d0f60a3..88b3c26b5 100644 --- a/BTCPayServer/Events/InvoiceEvent.cs +++ b/BTCPayServer/Events/InvoiceEvent.cs @@ -8,6 +8,18 @@ namespace BTCPayServer.Events { public class InvoiceEvent { + public const string Created = "invoice_created"; + public const string ReceivedPayment = "invoice_receivedPayment"; + public const string MarkedCompleted = "invoice_markedComplete"; + public const string MarkedInvalid= "invoice_markedInvalid"; + public const string Expired= "invoice_expired"; + public const string ExpiredPaidPartial= "invoice_expiredPaidPartial"; + public const string PaidInFull= "invoice_paidInFull"; + public const string PaidAfterExpiration= "invoice_paidAfterExpiration"; + public const string FailedToConfirm= "invoice_failedToConfirm"; + public const string Confirmed= "invoice_confirmed"; + public const string Completed= "invoice_completed"; + public InvoiceEvent(Models.InvoiceResponse invoice, int code, string name) { Invoice = invoice; @@ -19,6 +31,8 @@ namespace BTCPayServer.Events public int EventCode { get; set; } public string Name { get; set; } + public PaymentEntity Payment { get; set; } + public override string ToString() { return $"Invoice {Invoice.Id} new event: {Name} ({EventCode})"; diff --git a/BTCPayServer/HostedServices/InvoiceNotificationManager.cs b/BTCPayServer/HostedServices/InvoiceNotificationManager.cs index 455050373..b63d5d5d8 100644 --- a/BTCPayServer/HostedServices/InvoiceNotificationManager.cs +++ b/BTCPayServer/HostedServices/InvoiceNotificationManager.cs @@ -341,14 +341,14 @@ namespace BTCPayServer.HostedServices // we need to use the status in the event and not in the invoice. The invoice might now be in another status. if (invoice.FullNotifications) { - if (e.Name == "invoice_expired" || - e.Name == "invoice_paidInFull" || - e.Name == "invoice_failedToConfirm" || - e.Name == "invoice_markedInvalid" || - e.Name == "invoice_markedComplete" || - e.Name == "invoice_failedToConfirm" || - e.Name == "invoice_completed" || - e.Name == "invoice_expiredPaidPartial" + if (e.Name == InvoiceEvent.Expired || + e.Name == InvoiceEvent.PaidInFull || + e.Name == InvoiceEvent.FailedToConfirm || + e.Name == InvoiceEvent.MarkedInvalid || + e.Name == InvoiceEvent.MarkedCompleted || + e.Name == InvoiceEvent.FailedToConfirm || + e.Name == InvoiceEvent.Completed || + e.Name == InvoiceEvent.ExpiredPaidPartial ) tasks.Add(Notify(invoice)); } diff --git a/BTCPayServer/HostedServices/InvoiceWatcher.cs b/BTCPayServer/HostedServices/InvoiceWatcher.cs index c037a9724..7c9687bfc 100644 --- a/BTCPayServer/HostedServices/InvoiceWatcher.cs +++ b/BTCPayServer/HostedServices/InvoiceWatcher.cs @@ -66,10 +66,10 @@ namespace BTCPayServer.HostedServices context.MarkDirty(); await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1004, "invoice_expired")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1004, InvoiceEvent.Expired)); invoice.Status = InvoiceStatus.Expired; if(invoice.ExceptionStatus == InvoiceExceptionStatus.PaidPartial) - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2000, "invoice_expiredPaidPartial")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 2000, InvoiceEvent.ExpiredPaidPartial)); } var payments = invoice.GetPayments().Where(p => p.Accounted).ToArray(); @@ -84,7 +84,7 @@ namespace BTCPayServer.HostedServices { if (invoice.Status == InvoiceStatus.New) { - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1003, "invoice_paidInFull")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1003, InvoiceEvent.PaidInFull)); invoice.Status = InvoiceStatus.Paid; invoice.ExceptionStatus = accounting.Paid > accounting.TotalDue ? InvoiceExceptionStatus.PaidOver : InvoiceExceptionStatus.None; await _InvoiceRepository.UnaffectAddress(invoice.Id); @@ -93,7 +93,7 @@ namespace BTCPayServer.HostedServices else if (invoice.Status == InvoiceStatus.Expired && invoice.ExceptionStatus != InvoiceExceptionStatus.PaidLate) { invoice.ExceptionStatus = InvoiceExceptionStatus.PaidLate; - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1009, "invoice_paidAfterExpiration")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1009, InvoiceEvent.PaidAfterExpiration)); context.MarkDirty(); } } @@ -139,14 +139,14 @@ namespace BTCPayServer.HostedServices (confirmedAccounting.Paid < accounting.MinimumTotalDue)) { await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1013, "invoice_failedToConfirm")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1013, InvoiceEvent.FailedToConfirm)); invoice.Status = InvoiceStatus.Invalid; context.MarkDirty(); } else if (confirmedAccounting.Paid >= accounting.MinimumTotalDue) { await _InvoiceRepository.UnaffectAddress(invoice.Id); - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1005, "invoice_confirmed")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1005, InvoiceEvent.Confirmed)); invoice.Status = InvoiceStatus.Confirmed; context.MarkDirty(); } @@ -157,7 +157,7 @@ namespace BTCPayServer.HostedServices var completedAccounting = paymentMethod.Calculate(p => p.GetCryptoPaymentData().PaymentCompleted(p, network)); if (completedAccounting.Paid >= accounting.MinimumTotalDue) { - context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1006, "invoice_completed")); + context.Events.Add(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1006, InvoiceEvent.Completed)); invoice.Status = InvoiceStatus.Complete; context.MarkDirty(); } @@ -247,13 +247,13 @@ namespace BTCPayServer.HostedServices })); leases.Add(_EventAggregator.Subscribe(async b => { - if (b.Name == "invoice_created") + if (b.Name == InvoiceEvent.Created) { Watch(b.Invoice.Id); await Wait(b.Invoice.Id); } - if (b.Name == "invoice_receivedPayment") + if (b.Name == InvoiceEvent.ReceivedPayment) { Watch(b.Invoice.Id); } diff --git a/BTCPayServer/Models/InvoiceResponse.cs b/BTCPayServer/Models/InvoiceResponse.cs index df47d65a9..486a3b906 100644 --- a/BTCPayServer/Models/InvoiceResponse.cs +++ b/BTCPayServer/Models/InvoiceResponse.cs @@ -40,6 +40,12 @@ namespace BTCPayServer.Models //{"facade":"pos/invoice","data":{,}} public class InvoiceResponse { + [JsonIgnore] + public string StoreId + { + get; set; + } + //"url":"https://test.bitpay.com/invoice?id=9saCHtp1zyPcNoi3rDdBu8" [JsonProperty("url")] public string Url diff --git a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs index ad8acabc4..77b31d4f5 100644 --- a/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs +++ b/BTCPayServer/Payments/Bitcoin/NBXplorerListener.cs @@ -373,7 +373,7 @@ namespace BTCPayServer.Payments.Bitcoin invoice.SetPaymentMethod(paymentMethod); } wallet.InvalidateCache(strategy); - _Aggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1002, "invoice_receivedPayment")); + _Aggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1002, InvoiceEvent.ReceivedPayment){Payment = payment}); return invoice; } public Task StopAsync(CancellationToken cancellationToken) diff --git a/BTCPayServer/Payments/Lightning/LightningListener.cs b/BTCPayServer/Payments/Lightning/LightningListener.cs index e81e14400..6ec855458 100644 --- a/BTCPayServer/Payments/Lightning/LightningListener.cs +++ b/BTCPayServer/Payments/Lightning/LightningListener.cs @@ -42,7 +42,7 @@ namespace BTCPayServer.Payments.Lightning { leases.Add(_Aggregator.Subscribe(async inv => { - if (inv.Name == "invoice_created") + if (inv.Name == InvoiceEvent.Created) { await EnsureListening(inv.Invoice.Id, false); } @@ -197,7 +197,7 @@ namespace BTCPayServer.Payments.Lightning { var invoice = await _InvoiceRepository.GetInvoice(listenedInvoice.InvoiceId); if (invoice != null) - _Aggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1002, "invoice_receivedPayment")); + _Aggregator.Publish(new InvoiceEvent(invoice.EntityToDTO(_NetworkProvider), 1002, InvoiceEvent.ReceivedPayment){Payment = payment}); } }