mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 22:44:29 +01:00
Webhook tests + FIXES + DOCS (#5686)
* webhook tests * fixes and add docs * Do not update FormResponse and StoreId in update/create PullPayment --------- Co-authored-by: nicolas.dorier <nicolas.dorier@gmail.com>
This commit is contained in:
@@ -7,11 +7,11 @@ namespace BTCPayServer.Client.Models
|
|||||||
{
|
{
|
||||||
public class WebhookPayoutEvent : StoreWebhookEvent
|
public class WebhookPayoutEvent : StoreWebhookEvent
|
||||||
{
|
{
|
||||||
public WebhookPayoutEvent(string evtType, string storeId)
|
public WebhookPayoutEvent(string type, string storeId)
|
||||||
{
|
{
|
||||||
if (!evtType.StartsWith("payout", StringComparison.InvariantCultureIgnoreCase))
|
if (!type.StartsWith("payout", StringComparison.InvariantCultureIgnoreCase))
|
||||||
throw new ArgumentException("Invalid event type", nameof(evtType));
|
throw new ArgumentException("Invalid event type", nameof(type));
|
||||||
Type = evtType;
|
Type = type;
|
||||||
StoreId = storeId;
|
StoreId = storeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,11 +21,11 @@ namespace BTCPayServer.Client.Models
|
|||||||
}
|
}
|
||||||
public class WebhookPaymentRequestEvent : StoreWebhookEvent
|
public class WebhookPaymentRequestEvent : StoreWebhookEvent
|
||||||
{
|
{
|
||||||
public WebhookPaymentRequestEvent(string evtType, string storeId)
|
public WebhookPaymentRequestEvent(string type, string storeId)
|
||||||
{
|
{
|
||||||
if (!evtType.StartsWith("paymentrequest", StringComparison.InvariantCultureIgnoreCase))
|
if (!type.StartsWith("paymentrequest", StringComparison.InvariantCultureIgnoreCase))
|
||||||
throw new ArgumentException("Invalid event type", nameof(evtType));
|
throw new ArgumentException("Invalid event type", nameof(type));
|
||||||
Type = evtType;
|
Type = type;
|
||||||
StoreId = storeId;
|
StoreId = storeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2331,7 +2331,7 @@ namespace BTCPayServer.Tests
|
|||||||
if (marked == InvoiceStatus.Settled)
|
if (marked == InvoiceStatus.Settled)
|
||||||
{
|
{
|
||||||
Assert.Equal(InvoiceStatus.Settled, result.Status);
|
Assert.Equal(InvoiceStatus.Settled, result.Status);
|
||||||
user.AssertHasWebhookEvent<WebhookInvoiceSettledEvent>(WebhookEventType.InvoiceSettled,
|
await user.AssertHasWebhookEvent<WebhookInvoiceSettledEvent>(WebhookEventType.InvoiceSettled,
|
||||||
o =>
|
o =>
|
||||||
{
|
{
|
||||||
Assert.Equal(inv.Id, o.InvoiceId);
|
Assert.Equal(inv.Id, o.InvoiceId);
|
||||||
@@ -2341,7 +2341,7 @@ namespace BTCPayServer.Tests
|
|||||||
if (marked == InvoiceStatus.Invalid)
|
if (marked == InvoiceStatus.Invalid)
|
||||||
{
|
{
|
||||||
Assert.Equal(InvoiceStatus.Invalid, result.Status);
|
Assert.Equal(InvoiceStatus.Invalid, result.Status);
|
||||||
var evt = user.AssertHasWebhookEvent<WebhookInvoiceInvalidEvent>(WebhookEventType.InvoiceInvalid,
|
var evt = await user.AssertHasWebhookEvent<WebhookInvoiceInvalidEvent>(WebhookEventType.InvoiceInvalid,
|
||||||
o =>
|
o =>
|
||||||
{
|
{
|
||||||
Assert.Equal(inv.Id, o.InvoiceId);
|
Assert.Equal(inv.Id, o.InvoiceId);
|
||||||
|
|||||||
@@ -452,9 +452,9 @@ namespace BTCPayServer.Tests
|
|||||||
{
|
{
|
||||||
private Client.Models.StoreWebhookData _wh;
|
private Client.Models.StoreWebhookData _wh;
|
||||||
private FakeServer _server;
|
private FakeServer _server;
|
||||||
private readonly List<WebhookInvoiceEvent> _webhookEvents;
|
private readonly List<StoreWebhookEvent> _webhookEvents;
|
||||||
private CancellationTokenSource _cts;
|
private CancellationTokenSource _cts;
|
||||||
public WebhookListener(Client.Models.StoreWebhookData wh, FakeServer server, List<WebhookInvoiceEvent> webhookEvents)
|
public WebhookListener(Client.Models.StoreWebhookData wh, FakeServer server, List<StoreWebhookEvent> webhookEvents)
|
||||||
{
|
{
|
||||||
_wh = wh;
|
_wh = wh;
|
||||||
_server = server;
|
_server = server;
|
||||||
@@ -472,7 +472,7 @@ namespace BTCPayServer.Tests
|
|||||||
var callback = Encoding.UTF8.GetString(bytes);
|
var callback = Encoding.UTF8.GetString(bytes);
|
||||||
lock (_webhookEvents)
|
lock (_webhookEvents)
|
||||||
{
|
{
|
||||||
_webhookEvents.Add(JsonConvert.DeserializeObject<WebhookInvoiceEvent>(callback));
|
_webhookEvents.Add(JsonConvert.DeserializeObject<DummyStoreWebhookEvent>(callback));
|
||||||
}
|
}
|
||||||
req.Response.StatusCode = 200;
|
req.Response.StatusCode = 200;
|
||||||
_server.Done();
|
_server.Done();
|
||||||
@@ -485,8 +485,13 @@ namespace BTCPayServer.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WebhookInvoiceEvent> WebhookEvents { get; set; } = new List<WebhookInvoiceEvent>();
|
public class DummyStoreWebhookEvent : StoreWebhookEvent
|
||||||
public TEvent AssertHasWebhookEvent<TEvent>(string eventType, Action<TEvent> assert) where TEvent : class
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<StoreWebhookEvent> WebhookEvents { get; set; } = new List<StoreWebhookEvent>();
|
||||||
|
public async Task<TEvent> AssertHasWebhookEvent<TEvent>(string eventType, Action<TEvent> assert) where TEvent : class
|
||||||
{
|
{
|
||||||
int retry = 0;
|
int retry = 0;
|
||||||
retry:
|
retry:
|
||||||
@@ -510,7 +515,7 @@ retry:
|
|||||||
}
|
}
|
||||||
if (retry < 3)
|
if (retry < 3)
|
||||||
{
|
{
|
||||||
Thread.Sleep(1000);
|
await Task.Delay(1000);
|
||||||
retry++;
|
retry++;
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ using Xunit;
|
|||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
using Xunit.Sdk;
|
using Xunit.Sdk;
|
||||||
using CreateInvoiceRequest = BTCPayServer.Client.Models.CreateInvoiceRequest;
|
using CreateInvoiceRequest = BTCPayServer.Client.Models.CreateInvoiceRequest;
|
||||||
|
using CreatePaymentRequestRequest = BTCPayServer.Client.Models.CreatePaymentRequestRequest;
|
||||||
|
using MarkPayoutRequest = BTCPayServer.Client.Models.MarkPayoutRequest;
|
||||||
|
using PaymentRequestData = BTCPayServer.Client.Models.PaymentRequestData;
|
||||||
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
|
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
|
||||||
|
|
||||||
namespace BTCPayServer.Tests
|
namespace BTCPayServer.Tests
|
||||||
@@ -1943,6 +1946,173 @@ namespace BTCPayServer.Tests
|
|||||||
entity.GetPaymentMethods().First().Calculate();
|
entity.GetPaymentMethods().First().Calculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Fact()]
|
||||||
|
[Trait("Integration", "Integration")]
|
||||||
|
public async Task EnsureWebhooksTrigger()
|
||||||
|
{
|
||||||
|
using var tester = CreateServerTester();
|
||||||
|
await tester.StartAsync();
|
||||||
|
var user = tester.NewAccount();
|
||||||
|
await user.GrantAccessAsync();
|
||||||
|
user.RegisterDerivationScheme("BTC");
|
||||||
|
await user.SetupWebhook();
|
||||||
|
var client = await user.CreateClient();
|
||||||
|
|
||||||
|
|
||||||
|
var invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest()
|
||||||
|
{
|
||||||
|
Amount = 0.00m,
|
||||||
|
Currency = "BTC"
|
||||||
|
});;
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceCreated, (WebhookInvoiceEvent x)=> Assert.Equal(invoice.Id, x.InvoiceId));
|
||||||
|
|
||||||
|
//invoice payment webhooks
|
||||||
|
invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest()
|
||||||
|
{
|
||||||
|
Amount = 0.01m,
|
||||||
|
Currency = "BTC"
|
||||||
|
});
|
||||||
|
|
||||||
|
var invoicePaymentRequest = new BitcoinUrlBuilder((await client.GetInvoicePaymentMethods(user.StoreId, invoice.Id)).Single(model =>
|
||||||
|
PaymentMethodId.Parse(model.PaymentMethod) ==
|
||||||
|
new PaymentMethodId("BTC", BitcoinPaymentType.Instance))
|
||||||
|
.PaymentLink, tester.ExplorerNode.Network);
|
||||||
|
var halfPaymentTx = await tester.ExplorerNode.SendToAddressAsync(invoicePaymentRequest.Address, Money.Coins(invoicePaymentRequest.Amount.ToDecimal(MoneyUnit.BTC)/2m));
|
||||||
|
|
||||||
|
invoicePaymentRequest = new BitcoinUrlBuilder((await client.GetInvoicePaymentMethods(user.StoreId, invoice.Id)).Single(model =>
|
||||||
|
PaymentMethodId.Parse(model.PaymentMethod) ==
|
||||||
|
new PaymentMethodId("BTC", BitcoinPaymentType.Instance))
|
||||||
|
.PaymentLink, tester.ExplorerNode.Network);
|
||||||
|
var remainingPaymentTx = await tester.ExplorerNode.SendToAddressAsync(invoicePaymentRequest.Address, Money.Coins(invoicePaymentRequest.Amount.ToDecimal(MoneyUnit.BTC)));
|
||||||
|
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceCreated, (WebhookInvoiceEvent x)=> Assert.Equal(invoice.Id, x.InvoiceId));
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceProcessing, (WebhookInvoiceEvent x)=> Assert.Equal(invoice.Id, x.InvoiceId));
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceReceivedPayment,
|
||||||
|
(WebhookInvoiceReceivedPaymentEvent x) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(invoice.Id, x.InvoiceId);
|
||||||
|
Assert.Contains(halfPaymentTx.ToString(), x.Payment.Id);
|
||||||
|
});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceReceivedPayment,
|
||||||
|
(WebhookInvoiceReceivedPaymentEvent x) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(invoice.Id, x.InvoiceId);
|
||||||
|
Assert.Contains(remainingPaymentTx.ToString(), x.Payment.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.ExplorerNode.GenerateAsync(1);
|
||||||
|
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoicePaymentSettled,
|
||||||
|
(WebhookInvoiceReceivedPaymentEvent x) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(invoice.Id, x.InvoiceId);
|
||||||
|
Assert.Contains(halfPaymentTx.ToString(), x.Payment.Id);
|
||||||
|
});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoicePaymentSettled,
|
||||||
|
(WebhookInvoiceReceivedPaymentEvent x) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(invoice.Id, x.InvoiceId);
|
||||||
|
Assert.Contains(remainingPaymentTx.ToString(), x.Payment.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceSettled, (WebhookInvoiceEvent x)=> Assert.Equal(invoice.Id, x.InvoiceId));
|
||||||
|
|
||||||
|
invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest()
|
||||||
|
{
|
||||||
|
Amount = 0.01m,
|
||||||
|
Currency = "BTC",
|
||||||
|
});
|
||||||
|
invoicePaymentRequest = new BitcoinUrlBuilder((await client.GetInvoicePaymentMethods(user.StoreId, invoice.Id)).Single(model =>
|
||||||
|
PaymentMethodId.Parse(model.PaymentMethod) ==
|
||||||
|
new PaymentMethodId("BTC", BitcoinPaymentType.Instance))
|
||||||
|
.PaymentLink, tester.ExplorerNode.Network);
|
||||||
|
halfPaymentTx = await tester.ExplorerNode.SendToAddressAsync(invoicePaymentRequest.Address, Money.Coins(invoicePaymentRequest.Amount.ToDecimal(MoneyUnit.BTC)/2m));
|
||||||
|
|
||||||
|
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceCreated, (WebhookInvoiceEvent x)=> Assert.Equal(invoice.Id, x.InvoiceId));
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceReceivedPayment,
|
||||||
|
(WebhookInvoiceReceivedPaymentEvent x) =>
|
||||||
|
{
|
||||||
|
Assert.Equal(invoice.Id, x.InvoiceId);
|
||||||
|
Assert.Contains(halfPaymentTx.ToString(), x.Payment.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest()
|
||||||
|
{
|
||||||
|
Amount = 0.01m,
|
||||||
|
Currency = "BTC"
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceCreated, (WebhookInvoiceEvent x)=> Assert.Equal(invoice.Id, x.InvoiceId));
|
||||||
|
await client.MarkInvoiceStatus(user.StoreId, invoice.Id, new MarkInvoiceStatusRequest() { Status = InvoiceStatus.Invalid});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.InvoiceInvalid, (WebhookInvoiceEvent x)=> Assert.Equal(invoice.Id, x.InvoiceId));
|
||||||
|
|
||||||
|
//payment request webhook test
|
||||||
|
var pr = await client.CreatePaymentRequest(user.StoreId, new CreatePaymentRequestRequest()
|
||||||
|
{
|
||||||
|
Amount = 100m,
|
||||||
|
Currency = "USD",
|
||||||
|
Title = "test pr",
|
||||||
|
//TODO: this is a bug, we should not have these props in create request
|
||||||
|
StoreId = user.StoreId,
|
||||||
|
FormResponse = new JObject(),
|
||||||
|
//END todo
|
||||||
|
Description = "lala baba"
|
||||||
|
});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PaymentRequestCreated, (WebhookPaymentRequestEvent x)=> Assert.Equal(pr.Id, x.PaymentRequestId));
|
||||||
|
pr = await client.UpdatePaymentRequest(user.StoreId, pr.Id,
|
||||||
|
new UpdatePaymentRequestRequest() { Title = "test pr updated", Amount = 100m,
|
||||||
|
Currency = "USD",
|
||||||
|
//TODO: this is a bug, we should not have these props in create request
|
||||||
|
StoreId = user.StoreId,
|
||||||
|
FormResponse = new JObject(),
|
||||||
|
//END todo
|
||||||
|
Description = "lala baba"});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PaymentRequestUpdated, (WebhookPaymentRequestEvent x)=> Assert.Equal(pr.Id, x.PaymentRequestId));
|
||||||
|
var inv = await client.PayPaymentRequest(user.StoreId, pr.Id, new PayPaymentRequestRequest() {});
|
||||||
|
|
||||||
|
await client.MarkInvoiceStatus(user.StoreId, inv.Id, new MarkInvoiceStatusRequest() { Status = InvoiceStatus.Settled});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PaymentRequestStatusChanged, (WebhookPaymentRequestEvent x)=>
|
||||||
|
{
|
||||||
|
Assert.Equal(PaymentRequestData.PaymentRequestStatus.Completed, x.Status);
|
||||||
|
Assert.Equal(pr.Id, x.PaymentRequestId);
|
||||||
|
});
|
||||||
|
await client.ArchivePaymentRequest(user.StoreId, pr.Id);
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PaymentRequestArchived, (WebhookPaymentRequestEvent x)=> Assert.Equal(pr.Id, x.PaymentRequestId));
|
||||||
|
//payoyt webhooks test
|
||||||
|
var payout = await client.CreatePayout(user.StoreId,
|
||||||
|
new CreatePayoutThroughStoreRequest()
|
||||||
|
{
|
||||||
|
Amount = 0.0001m,
|
||||||
|
Destination = (await tester.ExplorerNode.GetNewAddressAsync()).ToString(),
|
||||||
|
Approved = true,
|
||||||
|
PaymentMethod = "BTC"
|
||||||
|
});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PayoutCreated, (WebhookPayoutEvent x)=> Assert.Equal(payout.Id, x.PayoutId));
|
||||||
|
await client.MarkPayout(user.StoreId, payout.Id, new MarkPayoutRequest(){ State = PayoutState.AwaitingApproval});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PayoutUpdated, (WebhookPayoutEvent x)=>
|
||||||
|
{
|
||||||
|
Assert.Equal(payout.Id, x.PayoutId);
|
||||||
|
Assert.Equal(PayoutState.AwaitingApproval, x.PayoutState);
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.ApprovePayout(user.StoreId, payout.Id, new ApprovePayoutRequest(){});
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PayoutApproved, (WebhookPayoutEvent x)=>
|
||||||
|
{
|
||||||
|
Assert.Equal(payout.Id, x.PayoutId);
|
||||||
|
Assert.Equal(PayoutState.AwaitingPayment, x.PayoutState);
|
||||||
|
});
|
||||||
|
await client.CancelPayout(user.StoreId, payout.Id );
|
||||||
|
await user.AssertHasWebhookEvent(WebhookEventType.PayoutUpdated, (WebhookPayoutEvent x)=>
|
||||||
|
{
|
||||||
|
Assert.Equal(payout.Id, x.PayoutId);
|
||||||
|
Assert.Equal(PayoutState.Cancelled, x.PayoutState);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Fact(Timeout = LongRunningTestTimeout)]
|
[Fact(Timeout = LongRunningTestTimeout)]
|
||||||
[Trait("Integration", "Integration")]
|
[Trait("Integration", "Integration")]
|
||||||
public async Task InvoiceFlowThroughDifferentStatesCorrectly()
|
public async Task InvoiceFlowThroughDifferentStatesCorrectly()
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
Status = Client.Models.PaymentRequestData.PaymentRequestStatus.Pending,
|
Status = Client.Models.PaymentRequestData.PaymentRequestStatus.Pending,
|
||||||
Created = DateTimeOffset.UtcNow
|
Created = DateTimeOffset.UtcNow
|
||||||
};
|
};
|
||||||
|
request.FormResponse = null;
|
||||||
|
request.StoreId = storeId;
|
||||||
pr.SetBlob(request);
|
pr.SetBlob(request);
|
||||||
pr = await _paymentRequestRepository.CreateOrUpdatePaymentRequest(pr);
|
pr = await _paymentRequestRepository.CreateOrUpdatePaymentRequest(pr);
|
||||||
return Ok(FromModel(pr));
|
return Ok(FromModel(pr));
|
||||||
@@ -196,6 +198,9 @@ namespace BTCPayServer.Controllers.Greenfield
|
|||||||
}
|
}
|
||||||
|
|
||||||
var updatedPr = pr.First();
|
var updatedPr = pr.First();
|
||||||
|
var blob = updatedPr.GetBlob();
|
||||||
|
request.FormResponse = blob.FormResponse;
|
||||||
|
request.StoreId = storeId;
|
||||||
updatedPr.SetBlob(request);
|
updatedPr.SetBlob(request);
|
||||||
|
|
||||||
return Ok(FromModel(await _paymentRequestRepository.CreateOrUpdatePaymentRequest(updatedPr)));
|
return Ok(FromModel(await _paymentRequestRepository.CreateOrUpdatePaymentRequest(updatedPr)));
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ namespace BTCPayServer.Data.Payouts.LightningLike
|
|||||||
{
|
{
|
||||||
if (payout.State != PayoutState.AwaitingPayment)
|
if (payout.State != PayoutState.AwaitingPayment)
|
||||||
{
|
{
|
||||||
_eventAggregator.Publish(new PayoutEvent(null, payout));
|
_eventAggregator.Publish(new PayoutEvent(PayoutEvent.PayoutEventType.Updated, payout));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -517,7 +517,7 @@ namespace BTCPayServer.HostedServices
|
|||||||
}
|
}
|
||||||
payout.State = req.Request.State;
|
payout.State = req.Request.State;
|
||||||
await ctx.SaveChangesAsync();
|
await ctx.SaveChangesAsync();
|
||||||
_eventAggregator.Publish(new PayoutEvent(null, payout));
|
_eventAggregator.Publish(new PayoutEvent(PayoutEvent.PayoutEventType.Updated, payout));
|
||||||
req.Completion.SetResult(MarkPayoutRequest.PayoutPaidResult.Ok);
|
req.Completion.SetResult(MarkPayoutRequest.PayoutPaidResult.Ok);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -739,7 +739,7 @@ namespace BTCPayServer.HostedServices
|
|||||||
foreach (var keyValuePair in result.Where(pair => pair.Value == MarkPayoutRequest.PayoutPaidResult.Ok))
|
foreach (var keyValuePair in result.Where(pair => pair.Value == MarkPayoutRequest.PayoutPaidResult.Ok))
|
||||||
{
|
{
|
||||||
var payout = payouts.First(p => p.Id == keyValuePair.Key);
|
var payout = payouts.First(p => p.Id == keyValuePair.Key);
|
||||||
_eventAggregator.Publish(new PayoutEvent(null, payout));
|
_eventAggregator.Publish(new PayoutEvent(PayoutEvent.PayoutEventType.Updated, payout));
|
||||||
}
|
}
|
||||||
cancel.Completion.TrySetResult(result);
|
cancel.Completion.TrySetResult(result);
|
||||||
}
|
}
|
||||||
@@ -959,7 +959,7 @@ namespace BTCPayServer.HostedServices
|
|||||||
public JObject Metadata { get; set; }
|
public JObject Metadata { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public record PayoutEvent(PayoutEvent.PayoutEventType? Type, PayoutData Payout)
|
public record PayoutEvent(PayoutEvent.PayoutEventType Type, PayoutData Payout)
|
||||||
{
|
{
|
||||||
public enum PayoutEventType
|
public enum PayoutEventType
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ public abstract class BaseAutomatedPayoutProcessor<T> : BaseAsyncService where T
|
|||||||
|
|
||||||
foreach (var payoutData in payouts.Where(payoutData => payoutData.State != PayoutState.AwaitingPayment))
|
foreach (var payoutData in payouts.Where(payoutData => payoutData.State != PayoutState.AwaitingPayment))
|
||||||
{
|
{
|
||||||
_eventAggregator.Publish(new PayoutEvent(null, payoutData));
|
_eventAggregator.Publish(new PayoutEvent(PayoutEvent.PayoutEventType.Updated, payoutData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1129,6 +1129,420 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"PaymentRequestCreated": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "Webhook_PaymentRequestCreated",
|
||||||
|
"summary": "PaymentRequestCreated",
|
||||||
|
"description": "A new payment request has been created",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "header",
|
||||||
|
"name": "BTCPay-Sig",
|
||||||
|
"required": true,
|
||||||
|
"description": "The HMAC of the body's byte with the secret's of the webhook. `sha256=HMAC256(UTF8(webhook's secret), body)`",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "sha256=b438519edde5c8144a4f9bcec51a9d346eca6506887c2ceeae1c0092884a97b9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Webhooks"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"paymentRequestId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Pending",
|
||||||
|
"Completed",
|
||||||
|
"Expired"
|
||||||
|
],
|
||||||
|
"description": "The status of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "Unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PaymentRequestUpdated": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "Webhook_PaymentRequestUpdated",
|
||||||
|
"summary": "PaymentRequestUpdated",
|
||||||
|
"description": "A payment request has been updated",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "header",
|
||||||
|
"name": "BTCPay-Sig",
|
||||||
|
"required": true,
|
||||||
|
"description": "The HMAC of the body's byte with the secret's of the webhook. `sha256=HMAC256(UTF8(webhook's secret), body)`",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "sha256=b438519edde5c8144a4f9bcec51a9d346eca6506887c2ceeae1c0092884a97b9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Webhooks"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"paymentRequestId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Pending",
|
||||||
|
"Completed",
|
||||||
|
"Expired"
|
||||||
|
],
|
||||||
|
"description": "The status of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "Unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PaymentRequestArchived": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "Webhook_PaymentRequestArchved",
|
||||||
|
"summary": "PaymentRequestArchived",
|
||||||
|
"description": "A payment request has been archived",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "header",
|
||||||
|
"name": "BTCPay-Sig",
|
||||||
|
"required": true,
|
||||||
|
"description": "The HMAC of the body's byte with the secret's of the webhook. `sha256=HMAC256(UTF8(webhook's secret), body)`",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "sha256=b438519edde5c8144a4f9bcec51a9d346eca6506887c2ceeae1c0092884a97b9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Webhooks"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"paymentRequestId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Pending",
|
||||||
|
"Completed",
|
||||||
|
"Expired"
|
||||||
|
],
|
||||||
|
"description": "The status of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "Unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PaymentRequestStatusChanged": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "Webhook_PaymentRequestStatusChanged",
|
||||||
|
"summary": "PaymentRequestStatusChanged",
|
||||||
|
"description": "A payment request has had its status changed",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "header",
|
||||||
|
"name": "BTCPay-Sig",
|
||||||
|
"required": true,
|
||||||
|
"description": "The HMAC of the body's byte with the secret's of the webhook. `sha256=HMAC256(UTF8(webhook's secret), body)`",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "sha256=b438519edde5c8144a4f9bcec51a9d346eca6506887c2ceeae1c0092884a97b9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Webhooks"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"paymentRequestId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Pending",
|
||||||
|
"Completed",
|
||||||
|
"Expired"
|
||||||
|
],
|
||||||
|
"description": "The status of the payment request",
|
||||||
|
"nullable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "Unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PayoutCreated": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "Webhook_PayoutCreated",
|
||||||
|
"summary": "PayoutCreated",
|
||||||
|
"description": "A payout has been created",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "header",
|
||||||
|
"name": "BTCPay-Sig",
|
||||||
|
"required": true,
|
||||||
|
"description": "The HMAC of the body's byte with the secret's of the webhook. `sha256=HMAC256(UTF8(webhook's secret), body)`",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "sha256=b438519edde5c8144a4f9bcec51a9d346eca6506887c2ceeae1c0092884a97b9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Webhooks"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"payoutId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the payout",
|
||||||
|
"nullable": false
|
||||||
|
},
|
||||||
|
"pullPaymentId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the pull payment this payout belongs to",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"payoutState": {
|
||||||
|
"$ref": "#/components/schemas/PayoutState"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "Unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PayoutApproved": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "Webhook_PayoutApproved",
|
||||||
|
"summary": "PayoutApproved",
|
||||||
|
"description": "A payout has been approved",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "header",
|
||||||
|
"name": "BTCPay-Sig",
|
||||||
|
"required": true,
|
||||||
|
"description": "The HMAC of the body's byte with the secret's of the webhook. `sha256=HMAC256(UTF8(webhook's secret), body)`",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "sha256=b438519edde5c8144a4f9bcec51a9d346eca6506887c2ceeae1c0092884a97b9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Webhooks"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"payoutId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the payout",
|
||||||
|
"nullable": false
|
||||||
|
},
|
||||||
|
"pullPaymentId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the pull payment this payout belongs to",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"payoutState": {
|
||||||
|
"$ref": "#/components/schemas/PayoutState"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "Unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PayoutUpdated": {
|
||||||
|
"post": {
|
||||||
|
"operationId": "Webhook_PayoutUpdated",
|
||||||
|
"summary": "PayoutUpdated",
|
||||||
|
"description": "A payout has been updated",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "header",
|
||||||
|
"name": "BTCPay-Sig",
|
||||||
|
"required": true,
|
||||||
|
"description": "The HMAC of the body's byte with the secret's of the webhook. `sha256=HMAC256(UTF8(webhook's secret), body)`",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "sha256=b438519edde5c8144a4f9bcec51a9d346eca6506887c2ceeae1c0092884a97b9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Webhooks"
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"payoutId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the payout",
|
||||||
|
"nullable": false
|
||||||
|
},
|
||||||
|
"pullPaymentId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The id of the pull payment this payout belongs to",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"payoutState": {
|
||||||
|
"$ref": "#/components/schemas/PayoutState"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"default": {
|
||||||
|
"description": "Unexpected error",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ProblemDetails"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tags": [
|
"tags": [
|
||||||
|
|||||||
Reference in New Issue
Block a user