mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
GreenField: Invoice API
This commit is contained in:
142
BTCPayServer.Client/Models/CreateInvoiceRequest.cs
Normal file
142
BTCPayServer.Client/Models/CreateInvoiceRequest.cs
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
using System;
|
||||||
|
using BTCPayServer.JsonConverters;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Client.Models
|
||||||
|
{
|
||||||
|
public class CreateInvoiceRequest
|
||||||
|
{
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal Amount
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Currency
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductInformation Metadata { get; set; }
|
||||||
|
|
||||||
|
public BuyerInformation Customer { get; set; } = new BuyerInformation();
|
||||||
|
|
||||||
|
public CheckoutOptions Checkout { get; set; } = new CheckoutOptions();
|
||||||
|
|
||||||
|
public class CheckoutOptions
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public SpeedPolicy? SpeedPolicy { get; set; }
|
||||||
|
|
||||||
|
public string[] PaymentMethods { get; set; }
|
||||||
|
public bool? RedirectAutomatically { get; set; }
|
||||||
|
public string RedirectUri { get; set; }
|
||||||
|
public Uri WebHook { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||||
|
public DateTimeOffset? ExpirationTime { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public double? PaymentTolerance { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BuyerInformation
|
||||||
|
{
|
||||||
|
[JsonProperty(PropertyName = "buyerName")]
|
||||||
|
public string BuyerName
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerEmail")]
|
||||||
|
public string BuyerEmail
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerCountry")]
|
||||||
|
public string BuyerCountry
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerZip")]
|
||||||
|
public string BuyerZip
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerState")]
|
||||||
|
public string BuyerState
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerCity")]
|
||||||
|
public string BuyerCity
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerAddress2")]
|
||||||
|
public string BuyerAddress2
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerAddress1")]
|
||||||
|
public string BuyerAddress1
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "buyerPhone")]
|
||||||
|
public string BuyerPhone
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProductInformation
|
||||||
|
{
|
||||||
|
public string OrderId { get; set; }
|
||||||
|
public string PosData { get; set; }
|
||||||
|
|
||||||
|
public string ItemDesc
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ItemCode
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Physical
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal? TaxIncluded
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
BTCPayServer.Client/Models/InvoiceData.cs
Normal file
70
BTCPayServer.Client/Models/InvoiceData.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using BTCPayServer.JsonConverters;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Client.Models
|
||||||
|
{
|
||||||
|
public class InvoiceData : CreateInvoiceRequest
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public Dictionary<string, PaymentMethodDataModel> PaymentMethodData { get; set; }
|
||||||
|
|
||||||
|
public class PaymentMethodDataModel
|
||||||
|
{
|
||||||
|
public string Destination { get; set; }
|
||||||
|
public string PaymentLink { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal Rate { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal PaymentMethodPaid { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal TotalPaid { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal Due { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal NetworkFee { get; set; }
|
||||||
|
|
||||||
|
public List<Payment> Payments { get; set; }
|
||||||
|
|
||||||
|
public class Payment
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(NBitcoin.JsonConverters.DateTimeToUnixTimeConverter))]
|
||||||
|
public DateTime ReceivedDate { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal Value { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty(ItemConverterType = typeof(DecimalDoubleStringJsonConverter))]
|
||||||
|
public decimal Fee { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public PaymentStatus Status { get; set; }
|
||||||
|
|
||||||
|
public string Destination { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public enum PaymentStatus
|
||||||
|
{
|
||||||
|
Invalid,
|
||||||
|
AwaitingConfirmation,
|
||||||
|
AwaitingCompletion,
|
||||||
|
Complete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ namespace BTCPayServer.Client
|
|||||||
public const string CanModifyStoreSettings = "btcpay.store.canmodifystoresettings";
|
public const string CanModifyStoreSettings = "btcpay.store.canmodifystoresettings";
|
||||||
public const string CanModifyStoreSettingsUnscoped = "btcpay.store.canmodifystoresettings:";
|
public const string CanModifyStoreSettingsUnscoped = "btcpay.store.canmodifystoresettings:";
|
||||||
public const string CanViewStoreSettings = "btcpay.store.canviewstoresettings";
|
public const string CanViewStoreSettings = "btcpay.store.canviewstoresettings";
|
||||||
|
public const string CanViewInvoices = "btcpay.store.canviewinvoices";
|
||||||
public const string CanCreateInvoice = "btcpay.store.cancreateinvoice";
|
public const string CanCreateInvoice = "btcpay.store.cancreateinvoice";
|
||||||
public const string CanViewPaymentRequests = "btcpay.store.canviewpaymentrequests";
|
public const string CanViewPaymentRequests = "btcpay.store.canviewpaymentrequests";
|
||||||
public const string CanModifyPaymentRequests = "btcpay.store.canmodifypaymentrequests";
|
public const string CanModifyPaymentRequests = "btcpay.store.canmodifypaymentrequests";
|
||||||
@@ -26,6 +27,7 @@ namespace BTCPayServer.Client
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
yield return CanViewInvoices;
|
||||||
yield return CanCreateInvoice;
|
yield return CanCreateInvoice;
|
||||||
yield return CanModifyServerSettings;
|
yield return CanModifyServerSettings;
|
||||||
yield return CanModifyStoreSettings;
|
yield return CanModifyStoreSettings;
|
||||||
@@ -153,6 +155,8 @@ namespace BTCPayServer.Client
|
|||||||
return true;
|
return true;
|
||||||
switch (subpolicy)
|
switch (subpolicy)
|
||||||
{
|
{
|
||||||
|
case Policies.CanViewInvoices when this.Policy == Policies.CanModifyStoreSettings:
|
||||||
|
case Policies.CanViewInvoices when this.Policy == Policies.CanViewStoreSettings:
|
||||||
case Policies.CanViewStoreSettings when this.Policy == Policies.CanModifyStoreSettings:
|
case Policies.CanViewStoreSettings when this.Policy == Policies.CanModifyStoreSettings:
|
||||||
case Policies.CanCreateInvoice when this.Policy == Policies.CanModifyStoreSettings:
|
case Policies.CanCreateInvoice when this.Policy == Policies.CanModifyStoreSettings:
|
||||||
case Policies.CanViewProfile when this.Policy == Policies.CanModifyProfile:
|
case Policies.CanViewProfile when this.Policy == Policies.CanModifyProfile:
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ using Newtonsoft.Json.Schema;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
using Xunit.Sdk;
|
using Xunit.Sdk;
|
||||||
|
using ProductInformation = BTCPayServer.Services.Invoices.ProductInformation;
|
||||||
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
|
using RatesViewModel = BTCPayServer.Models.StoreViewModels.RatesViewModel;
|
||||||
|
|
||||||
namespace BTCPayServer.Tests
|
namespace BTCPayServer.Tests
|
||||||
|
|||||||
270
BTCPayServer/Controllers/GreenField/InvoiceController.cs
Normal file
270
BTCPayServer/Controllers/GreenField/InvoiceController.cs
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Client;
|
||||||
|
using BTCPayServer.Payments;
|
||||||
|
using BTCPayServer.Security;
|
||||||
|
using BTCPayServer.Services.Invoices;
|
||||||
|
using BTCPayServer.Validation;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Cors;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
|
using NBitcoin;
|
||||||
|
using NBitpayClient;
|
||||||
|
using CreateInvoiceRequest = BTCPayServer.Client.Models.CreateInvoiceRequest;
|
||||||
|
using InvoiceData = BTCPayServer.Client.Models.InvoiceData;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Controllers.GreenField
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Authorize(AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
|
[EnableCors(CorsPolicies.All)]
|
||||||
|
public class GreenFieldInvoiceController : Controller
|
||||||
|
{
|
||||||
|
private readonly InvoiceController _invoiceController;
|
||||||
|
private readonly InvoiceRepository _invoiceRepository;
|
||||||
|
|
||||||
|
public GreenFieldInvoiceController(InvoiceController invoiceController, InvoiceRepository invoiceRepository)
|
||||||
|
{
|
||||||
|
_invoiceController = invoiceController;
|
||||||
|
_invoiceRepository = invoiceRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = Policies.CanViewInvoices,
|
||||||
|
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
|
[HttpGet("~/api/v1/stores/{storeId}/invoices/{invoiceId}")]
|
||||||
|
public async Task<IActionResult> GetInvoices(string storeId)
|
||||||
|
{
|
||||||
|
var store = HttpContext.GetStoreData();
|
||||||
|
if (store == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var invoices = await _invoiceRepository.GetInvoices(new InvoiceQuery() {StoreId = new[] {store.Id}});
|
||||||
|
|
||||||
|
return Ok(invoices.Select(ToModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Authorize(Policy = Policies.CanViewInvoices,
|
||||||
|
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
|
[HttpGet("~/api/v1/stores/{storeId}/invoices/{invoiceId}")]
|
||||||
|
public async Task<IActionResult> GetInvoice(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(ToModel(invoice));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = Policies.CanModifyStoreSettings,
|
||||||
|
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
|
[HttpDelete("~/api/v1/stores/{storeId}/invoices/{invoiceId}")]
|
||||||
|
public async Task<IActionResult> ArchiveInvoice(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();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _invoiceRepository.ToggleInvoiceArchival(invoiceId, true);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = Policies.CanCreateInvoice,
|
||||||
|
AuthenticationSchemes = AuthenticationSchemes.Greenfield)]
|
||||||
|
[HttpPost("~/api/v1/stores/{storeId}/invoices")]
|
||||||
|
public async Task<IActionResult> CreateInvoice(string storeId, CreateInvoiceRequest request)
|
||||||
|
{
|
||||||
|
var store = HttpContext.GetStoreData();
|
||||||
|
if (store == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Amount < 0.0m)
|
||||||
|
{
|
||||||
|
ModelState.AddModelError(nameof(request.Amount), "The amount should be 0 or more.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Checkout.PaymentMethods?.Any() is true)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < request.Checkout.PaymentMethods.Length; i++)
|
||||||
|
{
|
||||||
|
if (!PaymentMethodId.TryParse(request.Checkout.PaymentMethods[i], out _))
|
||||||
|
{
|
||||||
|
request.AddModelError(invoiceRequest => invoiceRequest.Checkout.PaymentMethods[i],
|
||||||
|
"Invalid payment method", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(request.Customer.BuyerEmail) &&
|
||||||
|
!EmailValidator.IsEmail(request.Customer.BuyerEmail))
|
||||||
|
{
|
||||||
|
request.AddModelError(invoiceRequest => invoiceRequest.Customer.BuyerEmail, "Invalid email address",
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Checkout.ExpirationTime != null && request.Checkout.ExpirationTime < DateTime.Now)
|
||||||
|
{
|
||||||
|
request.AddModelError(invoiceRequest => invoiceRequest.Checkout.ExpirationTime,
|
||||||
|
"Expiration time must be in the future", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Checkout.PaymentTolerance != null &&
|
||||||
|
(request.Checkout.PaymentTolerance < 0 || request.Checkout.PaymentTolerance > 100))
|
||||||
|
{
|
||||||
|
request.AddModelError(invoiceRequest => invoiceRequest.Checkout.PaymentTolerance,
|
||||||
|
"PaymentTolerance can only be between 0 and 100 percent", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ModelState.IsValid)
|
||||||
|
return this.CreateValidationError(ModelState);
|
||||||
|
|
||||||
|
var invoice = await _invoiceController.CreateInvoiceCoreRaw(FromModel(request), store,
|
||||||
|
Request.GetAbsoluteUri(""));
|
||||||
|
return Ok(ToModel(invoice));
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvoiceData ToModel(InvoiceEntity entity)
|
||||||
|
{
|
||||||
|
return new InvoiceData()
|
||||||
|
{
|
||||||
|
Amount = entity.ProductInformation.Price,
|
||||||
|
Id = entity.Id,
|
||||||
|
Currency = entity.ProductInformation.Currency,
|
||||||
|
Metadata =
|
||||||
|
new CreateInvoiceRequest.ProductInformation()
|
||||||
|
{
|
||||||
|
Physical = entity.ProductInformation.Physical,
|
||||||
|
ItemCode = entity.ProductInformation.ItemCode,
|
||||||
|
ItemDesc = entity.ProductInformation.ItemDesc,
|
||||||
|
OrderId = entity.OrderId,
|
||||||
|
PosData = entity.PosData,
|
||||||
|
TaxIncluded = entity.ProductInformation.TaxIncluded
|
||||||
|
},
|
||||||
|
Customer = new CreateInvoiceRequest.BuyerInformation()
|
||||||
|
{
|
||||||
|
BuyerAddress1 = entity.BuyerInformation.BuyerAddress1,
|
||||||
|
BuyerAddress2 = entity.BuyerInformation.BuyerAddress2,
|
||||||
|
BuyerCity = entity.BuyerInformation.BuyerCity,
|
||||||
|
BuyerCountry = entity.BuyerInformation.BuyerCountry,
|
||||||
|
BuyerEmail = entity.BuyerInformation.BuyerEmail,
|
||||||
|
BuyerName = entity.BuyerInformation.BuyerName,
|
||||||
|
BuyerPhone = entity.BuyerInformation.BuyerPhone,
|
||||||
|
BuyerState = entity.BuyerInformation.BuyerState,
|
||||||
|
BuyerZip = entity.BuyerInformation.BuyerZip
|
||||||
|
},
|
||||||
|
Checkout = new CreateInvoiceRequest.CheckoutOptions()
|
||||||
|
{
|
||||||
|
ExpirationTime = entity.ExpirationTime,
|
||||||
|
PaymentTolerance = entity.PaymentTolerance,
|
||||||
|
PaymentMethods =
|
||||||
|
entity.GetPaymentMethods().Select(method => method.GetId().ToString()).ToArray(),
|
||||||
|
RedirectAutomatically = entity.RedirectAutomatically,
|
||||||
|
RedirectUri = entity.RedirectURL.ToString(),
|
||||||
|
SpeedPolicy = entity.SpeedPolicy,
|
||||||
|
WebHook = entity.NotificationURL
|
||||||
|
},
|
||||||
|
PaymentMethodData = entity.GetPaymentMethods().ToDictionary(method => method.GetId().ToString(),
|
||||||
|
method =>
|
||||||
|
{
|
||||||
|
var accounting = method.Calculate();
|
||||||
|
var details = method.GetPaymentMethodDetails();
|
||||||
|
var payments = method.ParentEntity.GetPayments().Where(paymentEntity =>
|
||||||
|
paymentEntity.GetPaymentMethodId() == method.GetId());
|
||||||
|
|
||||||
|
return new InvoiceData.PaymentMethodDataModel()
|
||||||
|
{
|
||||||
|
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 InvoiceData.PaymentMethodDataModel.Payment()
|
||||||
|
{
|
||||||
|
Destination = data.GetDestination(),
|
||||||
|
Id = data.GetPaymentId(),
|
||||||
|
Status = !paymentEntity.Accounted
|
||||||
|
? InvoiceData.PaymentMethodDataModel.Payment.PaymentStatus.Invalid
|
||||||
|
: data.PaymentCompleted(paymentEntity)
|
||||||
|
? InvoiceData.PaymentMethodDataModel.Payment.PaymentStatus.Complete
|
||||||
|
: data.PaymentConfirmed(paymentEntity, entity.SpeedPolicy)
|
||||||
|
? InvoiceData.PaymentMethodDataModel.Payment.PaymentStatus
|
||||||
|
.AwaitingCompletion
|
||||||
|
: InvoiceData.PaymentMethodDataModel.Payment.PaymentStatus
|
||||||
|
.AwaitingConfirmation,
|
||||||
|
Fee = paymentEntity.NetworkFee,
|
||||||
|
Value = data.GetValue(),
|
||||||
|
ReceivedDate = paymentEntity.ReceivedTime.DateTime
|
||||||
|
};
|
||||||
|
}).ToList()
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Models.CreateInvoiceRequest FromModel(CreateInvoiceRequest entity)
|
||||||
|
{
|
||||||
|
return new Models.CreateInvoiceRequest()
|
||||||
|
{
|
||||||
|
Buyer = new Buyer()
|
||||||
|
{
|
||||||
|
country = entity.Customer.BuyerCountry,
|
||||||
|
email = entity.Customer.BuyerEmail,
|
||||||
|
phone = entity.Customer.BuyerPhone,
|
||||||
|
zip = entity.Customer.BuyerZip,
|
||||||
|
Address1 = entity.Customer.BuyerAddress1,
|
||||||
|
Address2 = entity.Customer.BuyerAddress2,
|
||||||
|
City = entity.Customer.BuyerCity,
|
||||||
|
Name = entity.Customer.BuyerName,
|
||||||
|
State = entity.Customer.BuyerState,
|
||||||
|
},
|
||||||
|
Currency = entity.Currency,
|
||||||
|
Physical = entity.Metadata.Physical,
|
||||||
|
Price = entity.Amount,
|
||||||
|
Refundable = true,
|
||||||
|
ExtendedNotifications = true,
|
||||||
|
FullNotifications = true,
|
||||||
|
RedirectURL = entity.Checkout.RedirectUri,
|
||||||
|
RedirectAutomatically = entity.Checkout.RedirectAutomatically,
|
||||||
|
ItemCode = entity.Metadata.ItemCode,
|
||||||
|
ItemDesc = entity.Metadata.ItemDesc,
|
||||||
|
ExpirationTime = entity.Checkout.ExpirationTime,
|
||||||
|
TransactionSpeed = entity.Checkout.SpeedPolicy?.ToString(),
|
||||||
|
PaymentCurrencies = entity.Checkout.PaymentMethods,
|
||||||
|
TaxIncluded = entity.Metadata.TaxIncluded,
|
||||||
|
OrderId = entity.Metadata.OrderId,
|
||||||
|
NotificationURL = entity.Checkout.RedirectUri,
|
||||||
|
PosData = entity.Metadata.PosData
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,8 @@ using NBitcoin;
|
|||||||
using NBitpayClient;
|
using NBitpayClient;
|
||||||
using NBXplorer;
|
using NBXplorer;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using CreateInvoiceRequest = BTCPayServer.Models.CreateInvoiceRequest;
|
||||||
|
using ProductInformation = BTCPayServer.Services.Invoices.ProductInformation;
|
||||||
using StoreData = BTCPayServer.Data.StoreData;
|
using StoreData = BTCPayServer.Data.StoreData;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ using Microsoft.AspNetCore.Identity;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using NBitpayClient;
|
using NBitpayClient;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using BuyerInformation = BTCPayServer.Services.Invoices.BuyerInformation;
|
||||||
using CreateInvoiceRequest = BTCPayServer.Models.CreateInvoiceRequest;
|
using CreateInvoiceRequest = BTCPayServer.Models.CreateInvoiceRequest;
|
||||||
|
using ProductInformation = BTCPayServer.Services.Invoices.ProductInformation;
|
||||||
using StoreData = BTCPayServer.Data.StoreData;
|
using StoreData = BTCPayServer.Data.StoreData;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
@@ -72,7 +74,16 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null, CancellationToken cancellationToken = default)
|
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(CreateInvoiceRequest invoice,
|
||||||
|
StoreData store, string serverUrl, List<string> additionalTags = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var entity = await CreateInvoiceCoreRaw(invoice, store, serverUrl, additionalTags, cancellationToken);
|
||||||
|
var resp = entity.EntityToDTO();
|
||||||
|
return new DataWrapper<InvoiceResponse>(resp) {Facade = "pos/invoice"};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
invoice.Currency = invoice.Currency?.ToUpperInvariant() ?? "USD";
|
invoice.Currency = invoice.Currency?.ToUpperInvariant() ?? "USD";
|
||||||
InvoiceLogs logs = new InvoiceLogs();
|
InvoiceLogs logs = new InvoiceLogs();
|
||||||
@@ -233,8 +244,7 @@ namespace BTCPayServer.Controllers
|
|||||||
await _InvoiceRepository.AddInvoiceLogs(entity.Id, logs);
|
await _InvoiceRepository.AddInvoiceLogs(entity.Id, logs);
|
||||||
});
|
});
|
||||||
_EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, InvoiceEvent.Created));
|
_EventAggregator.Publish(new Events.InvoiceEvent(entity, 1001, InvoiceEvent.Created));
|
||||||
var resp = entity.EntityToDTO();
|
return entity;
|
||||||
return new DataWrapper<InvoiceResponse>(resp) { Facade = "pos/invoice" };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task WhenAllFetched(InvoiceLogs logs, Dictionary<CurrencyPair, Task<RateResult>> fetchingByCurrencyPair)
|
private Task WhenAllFetched(InvoiceLogs logs, Dictionary<CurrencyPair, Task<RateResult>> fetchingByCurrencyPair)
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ namespace BTCPayServer.Controllers
|
|||||||
{BTCPayServer.Client.Policies.CanModifyProfile, ("Manage your profile", "The app will be able to view and modify your user profile.")},
|
{BTCPayServer.Client.Policies.CanModifyProfile, ("Manage your profile", "The app will be able to view and modify your user profile.")},
|
||||||
{BTCPayServer.Client.Policies.CanCreateInvoice, ("Create an invoice", "The app will be able to create new invoices.")},
|
{BTCPayServer.Client.Policies.CanCreateInvoice, ("Create an invoice", "The app will be able to create new invoices.")},
|
||||||
{$"{BTCPayServer.Client.Policies.CanCreateInvoice}:", ("Create an invoice", "The app will be able to create new invoices on the selected stores.")},
|
{$"{BTCPayServer.Client.Policies.CanCreateInvoice}:", ("Create an invoice", "The app will be able to create new invoices on the selected stores.")},
|
||||||
|
{BTCPayServer.Client.Policies.CanViewInvoices, ("View invoices", "The app will be able to view invoices.")},
|
||||||
|
{$"{BTCPayServer.Client.Policies.CanViewInvoices}:", ("View invoices", "The app will be able to view invoices on the selected stores.")},
|
||||||
{BTCPayServer.Client.Policies.CanModifyPaymentRequests, ("Modify your payment requests", "The app will be able to view, modify, delete and create new payment requests on all your stores.")},
|
{BTCPayServer.Client.Policies.CanModifyPaymentRequests, ("Modify your payment requests", "The app will be able to view, modify, delete and create new payment requests on all your stores.")},
|
||||||
{$"{BTCPayServer.Client.Policies.CanModifyPaymentRequests}:", ("Manage selected stores' payment requests", "The app will be able to view, modify, delete and create new payment requests on the selected stores.")},
|
{$"{BTCPayServer.Client.Policies.CanModifyPaymentRequests}:", ("Manage selected stores' payment requests", "The app will be able to view, modify, delete and create new payment requests on the selected stores.")},
|
||||||
{BTCPayServer.Client.Policies.CanViewPaymentRequests, ("View your payment requests", "The app will be able to view payment requests.")},
|
{BTCPayServer.Client.Policies.CanViewPaymentRequests, ("View your payment requests", "The app will be able to view payment requests.")},
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using BTCPayServer.Client.Models;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Payments.Bitcoin;
|
using BTCPayServer.Payments.Bitcoin;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using BuyerInformation = BTCPayServer.Services.Invoices.BuyerInformation;
|
||||||
|
using ProductInformation = BTCPayServer.Services.Invoices.ProductInformation;
|
||||||
|
|
||||||
namespace BTCPayServer.Models.InvoicingModels
|
namespace BTCPayServer.Models.InvoicingModels
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -465,7 +465,7 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
{
|
{
|
||||||
var minerInfo = new MinerFeeInfo();
|
var minerInfo = new MinerFeeInfo();
|
||||||
minerInfo.TotalFee = accounting.NetworkFee.Satoshi;
|
minerInfo.TotalFee = accounting.NetworkFee.Satoshi;
|
||||||
minerInfo.SatoshiPerBytes = ((BitcoinLikeOnChainPaymentMethod)details).FeeRate
|
minerInfo.SatoshiPerBytes = ((BitcoinLikeOnChainPaymentMethod) details).FeeRate
|
||||||
.GetFee(1).Satoshi;
|
.GetFee(1).Satoshi;
|
||||||
dto.MinerFees.TryAdd(cryptoInfo.CryptoCode, minerInfo);
|
dto.MinerFees.TryAdd(cryptoInfo.CryptoCode, minerInfo);
|
||||||
cryptoInfo.PaymentUrls = new InvoicePaymentUrls()
|
cryptoInfo.PaymentUrls = new InvoicePaymentUrls()
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Encoders = NBitcoin.DataEncoders.Encoders;
|
using Encoders = NBitcoin.DataEncoders.Encoders;
|
||||||
|
using InvoiceData = BTCPayServer.Data.InvoiceData;
|
||||||
|
|
||||||
namespace BTCPayServer.Services.Invoices
|
namespace BTCPayServer.Services.Invoices
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user