mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 09:54:30 +01:00
Merge pull request #1901 from btcpayserver/api/invoice-extras
GreenField: Add Invoice Payment methods endpoints
This commit is contained in:
commit
f9b86a6b2e
@ -26,6 +26,13 @@ namespace BTCPayServer.Client
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}"), token);
|
||||
return await HandleResponse<InvoiceData>(response);
|
||||
}
|
||||
public virtual async Task<InvoicePaymentMethodDataModel[]> GetInvoicePaymentMethods(string storeId, string invoiceId,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
var response = await _httpClient.SendAsync(
|
||||
CreateHttpRequest($"api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods"), token);
|
||||
return await HandleResponse<InvoicePaymentMethodDataModel[]>(response);
|
||||
}
|
||||
|
||||
public virtual async Task ArchiveInvoice(string storeId, string invoiceId,
|
||||
CancellationToken token = default)
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
|
61
BTCPayServer.Client/Models/InvoicePaymentMethodDataModel.cs
Normal file
61
BTCPayServer.Client/Models/InvoicePaymentMethodDataModel.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class InvoicePaymentMethodDataModel
|
||||
{
|
||||
public string Destination { get; set; }
|
||||
public string PaymentLink { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Rate { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal PaymentMethodPaid { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal TotalPaid { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Due { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal NetworkFee { get; set; }
|
||||
|
||||
public List<Payment> Payments { get; set; }
|
||||
public string PaymentMethod { get; set; }
|
||||
|
||||
public class Payment
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||
public DateTime ReceivedDate { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Value { get; set; }
|
||||
|
||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||
public decimal Fee { get; set; }
|
||||
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public PaymentStatus Status { get; set; }
|
||||
|
||||
public string Destination { get; set; }
|
||||
|
||||
public enum PaymentStatus
|
||||
{
|
||||
Invalid,
|
||||
AwaitingCompletion,
|
||||
Complete
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -945,9 +945,15 @@ namespace BTCPayServer.Tests
|
||||
Assert.Single(invoices);
|
||||
Assert.Equal(newInvoice.Id, invoices.First().Id);
|
||||
|
||||
//get payment request
|
||||
//get
|
||||
var invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id);
|
||||
Assert.Equal(newInvoice.Metadata, invoice.Metadata);
|
||||
var paymentMethods = await viewOnly.GetInvoicePaymentMethods(user.StoreId, newInvoice.Id);
|
||||
Assert.Equal(1, paymentMethods.Length);
|
||||
var paymentMethod = paymentMethods.First();
|
||||
Assert.Equal("BTC", paymentMethod.PaymentMethod);
|
||||
Assert.Equal(0, paymentMethod.Payments.Count);
|
||||
|
||||
|
||||
//update
|
||||
invoice = await viewOnly.GetInvoice(user.StoreId, newInvoice.Id);
|
||||
|
@ -213,8 +213,71 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
await _invoiceRepository.ToggleInvoiceArchival(invoiceId, false, storeId);
|
||||
return await GetInvoice(storeId, invoiceId);
|
||||
}
|
||||
|
||||
[Authorize(Policy = Policies.CanViewInvoices,
|
||||
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||
[HttpGet("~/api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods")]
|
||||
public async Task<IActionResult> GetInvoicePaymentMethods(string storeId, string invoiceId)
|
||||
{
|
||||
var store = HttpContext.GetStoreData();
|
||||
if (store == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var invoice = await _invoiceRepository.GetInvoice(invoiceId, true);
|
||||
if (invoice.StoreId != store.Id)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Ok(ToPaymentMethodModels(invoice));
|
||||
}
|
||||
|
||||
private InvoicePaymentMethodDataModel[] ToPaymentMethodModels(InvoiceEntity entity)
|
||||
{
|
||||
return entity.GetPaymentMethods().Select(
|
||||
method =>
|
||||
{
|
||||
var accounting = method.Calculate();
|
||||
var details = method.GetPaymentMethodDetails();
|
||||
var payments = method.ParentEntity.GetPayments().Where(paymentEntity =>
|
||||
paymentEntity.GetPaymentMethodId() == method.GetId());
|
||||
|
||||
return new InvoicePaymentMethodDataModel()
|
||||
{
|
||||
PaymentMethod = method.GetId().ToStringNormalized(),
|
||||
Destination = details.GetPaymentDestination(),
|
||||
Rate = method.Rate,
|
||||
Due = accounting.Due.ToDecimal(MoneyUnit.BTC),
|
||||
TotalPaid = accounting.Paid.ToDecimal(MoneyUnit.BTC),
|
||||
PaymentMethodPaid = accounting.CryptoPaid.ToDecimal(MoneyUnit.BTC),
|
||||
Amount = accounting.Due.ToDecimal(MoneyUnit.BTC),
|
||||
NetworkFee = accounting.NetworkFee.ToDecimal(MoneyUnit.BTC),
|
||||
PaymentLink =
|
||||
method.GetId().PaymentType.GetPaymentLink(method.Network, details, accounting.Due,
|
||||
Request.GetAbsoluteRoot()),
|
||||
Payments = payments.Select(paymentEntity =>
|
||||
{
|
||||
var data = paymentEntity.GetCryptoPaymentData();
|
||||
return new InvoicePaymentMethodDataModel.Payment()
|
||||
{
|
||||
Destination = data.GetDestination(),
|
||||
Id = data.GetPaymentId(),
|
||||
Status = !paymentEntity.Accounted
|
||||
? InvoicePaymentMethodDataModel.Payment.PaymentStatus.Invalid
|
||||
: data.PaymentConfirmed(paymentEntity, entity.SpeedPolicy) ||
|
||||
data.PaymentCompleted(paymentEntity)
|
||||
? InvoicePaymentMethodDataModel.Payment.PaymentStatus.Complete
|
||||
: InvoicePaymentMethodDataModel.Payment.PaymentStatus.AwaitingCompletion,
|
||||
Fee = paymentEntity.NetworkFee,
|
||||
Value = data.GetValue(),
|
||||
ReceivedDate = paymentEntity.ReceivedTime.DateTime
|
||||
};
|
||||
}).ToList()
|
||||
};
|
||||
}).ToArray();
|
||||
}
|
||||
private InvoiceData ToModel(InvoiceEntity entity)
|
||||
{
|
||||
return new InvoiceData()
|
||||
|
@ -216,6 +216,123 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/stores/{storeId}/invoices/{invoiceId}/payment-methods": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Invoices"
|
||||
],
|
||||
"summary": "Get invoice payment methods",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "storeId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The store to fetch",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "invoiceId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The invoice to fetch",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"description": "View information about the specified invoice's payment methods",
|
||||
"operationId": "Invoices_GetInvoicePaymentMethods",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "specified invoice payment methods data",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"nullable": false,
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/InvoicePaymentMethodDataModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "If you are authenticated but forbidden to view the specified invoie"
|
||||
},
|
||||
"404": {
|
||||
"description": "The key is not found for this invoice"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"API Key": [
|
||||
"btcpay.store.canviewinvoices"
|
||||
],
|
||||
"Basic": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Invoices"
|
||||
],
|
||||
"summary": "Archive invoice",
|
||||
"description": "Archives the specified invoice.",
|
||||
"operationId": "Invoices_ArchiveInvoice",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "storeId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The store the invoice belongs to",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "invoiceId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"description": "The invoice to remove",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The invoice has been archived"
|
||||
},
|
||||
"400": {
|
||||
"description": "A list of errors that occurred when archiving the invoice",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidationProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "If you are authenticated but forbidden to archive the specified invoice"
|
||||
},
|
||||
"404": {
|
||||
"description": "The key is not found for this invoice"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"API Key": [
|
||||
"btcpay.store.canmodifystoresettings"
|
||||
],
|
||||
"Basic": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/api/v1/stores/{storeId}/invoices/{invoiceId}/status": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@ -565,6 +682,110 @@
|
||||
"LowSpeed",
|
||||
"LowMediumSpeed"
|
||||
]
|
||||
},
|
||||
"InvoicePaymentMethodDataModel": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"paymentMethod": {
|
||||
"type": "string",
|
||||
"description": "The payment method"
|
||||
},
|
||||
"destination": {
|
||||
"type": "string",
|
||||
"description": "The destination the payment must be made to"
|
||||
},
|
||||
"paymentLink": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "A payment link that helps pay to the payment destination"
|
||||
},
|
||||
"rate": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The rate between this payment method's currency and the invoice currency"
|
||||
},
|
||||
"paymentMethodPaid": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The amount paid by this payment method"
|
||||
},
|
||||
"totalPaid": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The total amount paid by all payment methods to the invoice, converted to this payment method's currency"
|
||||
},
|
||||
"due": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The total amount left to be paid, converted to this payment method's currency"
|
||||
},
|
||||
"amount": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The invoice amount, converted to this payment method's currency"
|
||||
},
|
||||
"networkFee": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The added merchant fee to pay for network costs of this payment method."
|
||||
},
|
||||
"payments": {
|
||||
"type": "array",
|
||||
"nullable": false,
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Payment"
|
||||
},
|
||||
"description": "Payments made with this payment method."
|
||||
}
|
||||
}
|
||||
},
|
||||
"Payment": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "A unique identifier for this payment"
|
||||
},
|
||||
"receivedDate": {
|
||||
"type": "string",
|
||||
"format": "int64",
|
||||
"description": "The date the payment was recorded"
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The value of the payment"
|
||||
},
|
||||
"fee": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The fee paid for the payment"
|
||||
},
|
||||
"status": {
|
||||
"$ref": "#/components/schemas/PaymentStatus",
|
||||
"description": "The status of the payment"
|
||||
},
|
||||
"destination": {
|
||||
"type": "string",
|
||||
"description": "The destination the payment was made to"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PaymentStatus": {
|
||||
"type": "string",
|
||||
"description": "",
|
||||
"x-enumNames": [
|
||||
"Invalid",
|
||||
"AwaitingCompletion",
|
||||
"Complete"
|
||||
],
|
||||
"enum": [
|
||||
"Invalid",
|
||||
"AwaitingCompletion",
|
||||
"Complete"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -299,7 +299,7 @@
|
||||
"type": "string",
|
||||
"description": "The creation date of the payment request",
|
||||
"nullable": false,
|
||||
"format": "date-time"
|
||||
"format": "int64"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -342,7 +342,7 @@
|
||||
"type": "string",
|
||||
"description": "The expiry date of the payment request",
|
||||
"nullable": true,
|
||||
"format": "date-time"
|
||||
"format": "int64"
|
||||
},
|
||||
"embeddedCSS": {
|
||||
"type": "string",
|
||||
|
Loading…
Reference in New Issue
Block a user