mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Stop using bitpay's CreateInvoice for non bitpay API usage (#5184)
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -196,6 +197,7 @@ retry:
|
|||||||
driver.FindElement(selector).Click();
|
driver.FindElement(selector).Click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DebuggerHidden]
|
||||||
public static bool ElementDoesNotExist(this IWebDriver driver, By selector)
|
public static bool ElementDoesNotExist(this IWebDriver driver, By selector)
|
||||||
{
|
{
|
||||||
Assert.Throws<NoSuchElementException>(() =>
|
Assert.Throws<NoSuchElementException>(() =>
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Abstractions.Constants;
|
using BTCPayServer.Abstractions.Constants;
|
||||||
using BTCPayServer.Abstractions.Extensions;
|
using BTCPayServer.Abstractions.Extensions;
|
||||||
using BTCPayServer.Client;
|
using BTCPayServer.Client;
|
||||||
|
using BTCPayServer.Client.Models;
|
||||||
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
using BTCPayServer.ModelBinders;
|
using BTCPayServer.ModelBinders;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Payments;
|
||||||
|
using BTCPayServer.Security.Greenfield;
|
||||||
using BTCPayServer.Services.Invoices;
|
using BTCPayServer.Services.Invoices;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NBitpayClient;
|
||||||
|
using StoreData = BTCPayServer.Data.StoreData;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
@@ -36,7 +42,7 @@ namespace BTCPayServer.Controllers
|
|||||||
{
|
{
|
||||||
if (invoice == null)
|
if (invoice == null)
|
||||||
throw new BitpayHttpException(400, "Invalid invoice");
|
throw new BitpayHttpException(400, "Invalid invoice");
|
||||||
return await _InvoiceController.CreateInvoiceCore(invoice, HttpContext.GetStoreData(), HttpContext.Request.GetAbsoluteRoot(), cancellationToken: cancellationToken);
|
return await CreateInvoiceCore(invoice, HttpContext.GetStoreData(), HttpContext.Request.GetAbsoluteRoot(), cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@@ -66,7 +72,7 @@ namespace BTCPayServer.Controllers
|
|||||||
int? limit = null,
|
int? limit = null,
|
||||||
int? offset = null)
|
int? offset = null)
|
||||||
{
|
{
|
||||||
if (User.Identity.AuthenticationType == Security.Bitpay.BitpayAuthenticationTypes.Anonymous)
|
if (User.Identity?.AuthenticationType == Security.Bitpay.BitpayAuthenticationTypes.Anonymous)
|
||||||
return Forbid(Security.Bitpay.BitpayAuthenticationTypes.Anonymous);
|
return Forbid(Security.Bitpay.BitpayAuthenticationTypes.Anonymous);
|
||||||
if (dateEnd != null)
|
if (dateEnd != null)
|
||||||
dateEnd = dateEnd.Value + TimeSpan.FromDays(1); //Should include the end day
|
dateEnd = dateEnd.Value + TimeSpan.FromDays(1); //Should include the end day
|
||||||
@@ -88,5 +94,133 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
return Json(DataWrapper.Create(entities));
|
return Json(DataWrapper.Create(entities));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(BitpayCreateInvoiceRequest invoice,
|
||||||
|
StoreData store, string serverUrl, List<string> additionalTags = null,
|
||||||
|
CancellationToken cancellationToken = default, Action<InvoiceEntity> entityManipulator = null)
|
||||||
|
{
|
||||||
|
var entity = await CreateInvoiceCoreRaw(invoice, store, serverUrl, additionalTags, cancellationToken, entityManipulator);
|
||||||
|
var resp = entity.EntityToDTO();
|
||||||
|
return new DataWrapper<InvoiceResponse>(resp) { Facade = "pos/invoice" };
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null, CancellationToken cancellationToken = default, Action<InvoiceEntity> entityManipulator = null)
|
||||||
|
{
|
||||||
|
var storeBlob = store.GetStoreBlob();
|
||||||
|
var entity = _InvoiceRepository.CreateNewInvoice(store.Id);
|
||||||
|
entity.ExpirationTime = invoice.ExpirationTime is { } v ? v : entity.InvoiceTime + storeBlob.InvoiceExpiration;
|
||||||
|
entity.MonitoringExpiration = entity.ExpirationTime + storeBlob.MonitoringExpiration;
|
||||||
|
if (entity.ExpirationTime - TimeSpan.FromSeconds(30.0) < entity.InvoiceTime)
|
||||||
|
{
|
||||||
|
throw new BitpayHttpException(400, "The expirationTime is set too soon");
|
||||||
|
}
|
||||||
|
if (entity.Price < 0.0m)
|
||||||
|
{
|
||||||
|
throw new BitpayHttpException(400, "The price should be 0 or more.");
|
||||||
|
}
|
||||||
|
if (entity.Price > GreenfieldConstants.MaxAmount)
|
||||||
|
{
|
||||||
|
throw new BitpayHttpException(400, $"The price should less than {GreenfieldConstants.MaxAmount}.");
|
||||||
|
}
|
||||||
|
entity.Metadata.OrderId = invoice.OrderId;
|
||||||
|
entity.Metadata.PosDataLegacy = invoice.PosData;
|
||||||
|
entity.ServerUrl = serverUrl;
|
||||||
|
entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications;
|
||||||
|
entity.ExtendedNotifications = invoice.ExtendedNotifications;
|
||||||
|
entity.NotificationURLTemplate = invoice.NotificationURL;
|
||||||
|
entity.NotificationEmail = invoice.NotificationEmail;
|
||||||
|
if (additionalTags != null)
|
||||||
|
entity.InternalTags.AddRange(additionalTags);
|
||||||
|
FillBuyerInfo(invoice, entity);
|
||||||
|
|
||||||
|
var price = invoice.Price;
|
||||||
|
entity.Metadata.ItemCode = invoice.ItemCode;
|
||||||
|
entity.Metadata.ItemDesc = invoice.ItemDesc;
|
||||||
|
entity.Metadata.Physical = invoice.Physical;
|
||||||
|
entity.Metadata.TaxIncluded = invoice.TaxIncluded;
|
||||||
|
entity.Currency = invoice.Currency;
|
||||||
|
if (price is { } vv)
|
||||||
|
{
|
||||||
|
entity.Price = vv;
|
||||||
|
entity.Type = InvoiceType.Standard;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entity.Price = 0m;
|
||||||
|
entity.Type = InvoiceType.TopUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.StoreSupportUrl = storeBlob.StoreSupportUrl;
|
||||||
|
entity.RedirectURLTemplate = invoice.RedirectURL ?? store.StoreWebsite;
|
||||||
|
entity.RedirectAutomatically =
|
||||||
|
invoice.RedirectAutomatically.GetValueOrDefault(storeBlob.RedirectAutomatically);
|
||||||
|
entity.RequiresRefundEmail = invoice.RequiresRefundEmail;
|
||||||
|
entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);
|
||||||
|
|
||||||
|
IPaymentFilter excludeFilter = null;
|
||||||
|
if (invoice.PaymentCurrencies?.Any() is true)
|
||||||
|
{
|
||||||
|
invoice.SupportedTransactionCurrencies ??=
|
||||||
|
new Dictionary<string, InvoiceSupportedTransactionCurrency>();
|
||||||
|
foreach (string paymentCurrency in invoice.PaymentCurrencies)
|
||||||
|
{
|
||||||
|
invoice.SupportedTransactionCurrencies.TryAdd(paymentCurrency,
|
||||||
|
new InvoiceSupportedTransactionCurrency() { Enabled = true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (invoice.SupportedTransactionCurrencies != null && invoice.SupportedTransactionCurrencies.Count != 0)
|
||||||
|
{
|
||||||
|
var supportedTransactionCurrencies = invoice.SupportedTransactionCurrencies
|
||||||
|
.Where(c => c.Value.Enabled)
|
||||||
|
.Select(c => PaymentMethodId.TryParse(c.Key, out var p) ? p : null)
|
||||||
|
.Where(c => c != null)
|
||||||
|
.ToHashSet();
|
||||||
|
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
|
||||||
|
}
|
||||||
|
entity.PaymentTolerance = storeBlob.PaymentTolerance;
|
||||||
|
entity.DefaultPaymentMethod = invoice.DefaultPaymentMethod;
|
||||||
|
entity.RequiresRefundEmail = invoice.RequiresRefundEmail;
|
||||||
|
|
||||||
|
return await _InvoiceController.CreateInvoiceCoreRaw(entity, store, excludeFilter, null, cancellationToken, entityManipulator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillBuyerInfo(BitpayCreateInvoiceRequest req, InvoiceEntity invoiceEntity)
|
||||||
|
{
|
||||||
|
var buyerInformation = invoiceEntity.Metadata;
|
||||||
|
buyerInformation.BuyerAddress1 = req.BuyerAddress1;
|
||||||
|
buyerInformation.BuyerAddress2 = req.BuyerAddress2;
|
||||||
|
buyerInformation.BuyerCity = req.BuyerCity;
|
||||||
|
buyerInformation.BuyerCountry = req.BuyerCountry;
|
||||||
|
buyerInformation.BuyerEmail = req.BuyerEmail;
|
||||||
|
buyerInformation.BuyerName = req.BuyerName;
|
||||||
|
buyerInformation.BuyerPhone = req.BuyerPhone;
|
||||||
|
buyerInformation.BuyerState = req.BuyerState;
|
||||||
|
buyerInformation.BuyerZip = req.BuyerZip;
|
||||||
|
var buyer = req.Buyer;
|
||||||
|
if (buyer == null)
|
||||||
|
return;
|
||||||
|
buyerInformation.BuyerAddress1 ??= buyer.Address1;
|
||||||
|
buyerInformation.BuyerAddress2 ??= buyer.Address2;
|
||||||
|
buyerInformation.BuyerCity ??= buyer.City;
|
||||||
|
buyerInformation.BuyerCountry ??= buyer.country;
|
||||||
|
buyerInformation.BuyerEmail ??= buyer.email;
|
||||||
|
buyerInformation.BuyerName ??= buyer.Name;
|
||||||
|
buyerInformation.BuyerPhone ??= buyer.phone;
|
||||||
|
buyerInformation.BuyerState ??= buyer.State;
|
||||||
|
buyerInformation.BuyerZip ??= buyer.zip;
|
||||||
|
}
|
||||||
|
private SpeedPolicy ParseSpeedPolicy(string transactionSpeed, SpeedPolicy defaultPolicy)
|
||||||
|
{
|
||||||
|
if (transactionSpeed == null)
|
||||||
|
return defaultPolicy;
|
||||||
|
var mappings = new Dictionary<string, SpeedPolicy>();
|
||||||
|
mappings.Add("low", SpeedPolicy.LowSpeed);
|
||||||
|
mappings.Add("low-medium", SpeedPolicy.LowMediumSpeed);
|
||||||
|
mappings.Add("medium", SpeedPolicy.MediumSpeed);
|
||||||
|
mappings.Add("high", SpeedPolicy.HighSpeed);
|
||||||
|
if (!mappings.TryGetValue(transactionSpeed, out SpeedPolicy policy))
|
||||||
|
policy = defaultPolicy;
|
||||||
|
return policy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1280,32 +1280,40 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await CreateInvoiceCore(new BitpayCreateInvoiceRequest
|
var result = await CreateInvoiceCoreRaw(new CreateInvoiceRequest()
|
||||||
{
|
{
|
||||||
Price = model.Amount,
|
Amount = model.Amount,
|
||||||
Currency = model.Currency,
|
Currency = model.Currency,
|
||||||
PosData = model.PosData,
|
Metadata = new InvoiceMetadata()
|
||||||
OrderId = model.OrderId,
|
|
||||||
NotificationURL = model.NotificationUrl,
|
|
||||||
ItemDesc = model.ItemDesc,
|
|
||||||
FullNotifications = true,
|
|
||||||
BuyerEmail = model.BuyerEmail,
|
|
||||||
SupportedTransactionCurrencies = model.SupportedTransactionCurrencies?.ToDictionary(s => s, s => new InvoiceSupportedTransactionCurrency
|
|
||||||
{
|
{
|
||||||
Enabled = true
|
PosDataLegacy = model.PosData,
|
||||||
}),
|
OrderId = model.OrderId,
|
||||||
DefaultPaymentMethod = model.DefaultPaymentMethod,
|
ItemDesc = model.ItemDesc,
|
||||||
NotificationEmail = model.NotificationEmail,
|
BuyerEmail = model.BuyerEmail,
|
||||||
ExtendedNotifications = model.NotificationEmail != null,
|
}.ToJObject(),
|
||||||
RequiresRefundEmail = model.RequiresRefundEmail == RequiresRefundEmail.InheritFromStore
|
Checkout = new ()
|
||||||
? storeBlob.RequiresRefundEmail
|
{
|
||||||
: model.RequiresRefundEmail == RequiresRefundEmail.On,
|
RedirectURL = store.StoreWebsite,
|
||||||
}, store, HttpContext.Request.GetAbsoluteRoot(), cancellationToken: cancellationToken);
|
DefaultPaymentMethod = model.DefaultPaymentMethod,
|
||||||
|
RequiresRefundEmail = model.RequiresRefundEmail == RequiresRefundEmail.InheritFromStore
|
||||||
|
? storeBlob.RequiresRefundEmail
|
||||||
|
: model.RequiresRefundEmail == RequiresRefundEmail.On,
|
||||||
|
PaymentMethods = model.SupportedTransactionCurrencies?.ToArray()
|
||||||
|
},
|
||||||
|
}, store, HttpContext.Request.GetAbsoluteRoot(),
|
||||||
|
entityManipulator: (entity) =>
|
||||||
|
{
|
||||||
|
entity.NotificationURLTemplate = model.NotificationUrl;
|
||||||
|
entity.FullNotifications = true;
|
||||||
|
entity.NotificationEmail = model.NotificationEmail;
|
||||||
|
entity.ExtendedNotifications = model.NotificationEmail != null;
|
||||||
|
},
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
TempData[WellKnownTempData.SuccessMessage] = $"Invoice {result.Data.Id} just created!";
|
TempData[WellKnownTempData.SuccessMessage] = $"Invoice {result.Id} just created!";
|
||||||
CreatedInvoiceId = result.Data.Id;
|
CreatedInvoiceId = result.Id;
|
||||||
|
|
||||||
return RedirectToAction(nameof(Invoice), new { storeId = result.Data.StoreId, invoiceId = result.Data.Id });
|
return RedirectToAction(nameof(Invoice), new { storeId = result.StoreId, invoiceId = result.Id });
|
||||||
}
|
}
|
||||||
catch (BitpayHttpException ex)
|
catch (BitpayHttpException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ using BTCPayServer.Data;
|
|||||||
using BTCPayServer.Events;
|
using BTCPayServer.Events;
|
||||||
using BTCPayServer.HostedServices;
|
using BTCPayServer.HostedServices;
|
||||||
using BTCPayServer.Logging;
|
using BTCPayServer.Logging;
|
||||||
using BTCPayServer.Models;
|
|
||||||
using BTCPayServer.Models.PaymentRequestViewModels;
|
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Payments.Bitcoin;
|
using BTCPayServer.Payments.Bitcoin;
|
||||||
using BTCPayServer.Rating;
|
using BTCPayServer.Rating;
|
||||||
@@ -24,16 +22,13 @@ using BTCPayServer.Services.Invoices;
|
|||||||
using BTCPayServer.Services.PaymentRequests;
|
using BTCPayServer.Services.PaymentRequests;
|
||||||
using BTCPayServer.Services.Rates;
|
using BTCPayServer.Services.Rates;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
using BTCPayServer.Validation;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using NBitcoin;
|
using NBitcoin;
|
||||||
using NBitpayClient;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using BitpayCreateInvoiceRequest = BTCPayServer.Models.BitpayCreateInvoiceRequest;
|
|
||||||
using StoreData = BTCPayServer.Data.StoreData;
|
using StoreData = BTCPayServer.Data.StoreData;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
@@ -108,98 +103,6 @@ namespace BTCPayServer.Controllers
|
|||||||
_appService = appService;
|
_appService = appService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal async Task<DataWrapper<InvoiceResponse>> CreateInvoiceCore(BitpayCreateInvoiceRequest invoice,
|
|
||||||
StoreData store, string serverUrl, List<string>? additionalTags = null,
|
|
||||||
CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
|
|
||||||
{
|
|
||||||
var entity = await CreateInvoiceCoreRaw(invoice, store, serverUrl, additionalTags, cancellationToken, entityManipulator);
|
|
||||||
var resp = entity.EntityToDTO();
|
|
||||||
return new DataWrapper<InvoiceResponse>(resp) { Facade = "pos/invoice" };
|
|
||||||
}
|
|
||||||
|
|
||||||
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(BitpayCreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string>? additionalTags = null, CancellationToken cancellationToken = default, Action<InvoiceEntity>? entityManipulator = null)
|
|
||||||
{
|
|
||||||
var storeBlob = store.GetStoreBlob();
|
|
||||||
var entity = _InvoiceRepository.CreateNewInvoice(store.Id);
|
|
||||||
entity.ExpirationTime = invoice.ExpirationTime is DateTimeOffset v ? v : entity.InvoiceTime + storeBlob.InvoiceExpiration;
|
|
||||||
entity.MonitoringExpiration = entity.ExpirationTime + storeBlob.MonitoringExpiration;
|
|
||||||
if (entity.ExpirationTime - TimeSpan.FromSeconds(30.0) < entity.InvoiceTime)
|
|
||||||
{
|
|
||||||
throw new BitpayHttpException(400, "The expirationTime is set too soon");
|
|
||||||
}
|
|
||||||
if (entity.Price < 0.0m)
|
|
||||||
{
|
|
||||||
throw new BitpayHttpException(400, "The price should be 0 or more.");
|
|
||||||
}
|
|
||||||
if (entity.Price > GreenfieldConstants.MaxAmount)
|
|
||||||
{
|
|
||||||
throw new BitpayHttpException(400, $"The price should less than {GreenfieldConstants.MaxAmount}.");
|
|
||||||
}
|
|
||||||
entity.Metadata.OrderId = invoice.OrderId;
|
|
||||||
entity.Metadata.PosDataLegacy = invoice.PosData;
|
|
||||||
entity.ServerUrl = serverUrl;
|
|
||||||
entity.FullNotifications = invoice.FullNotifications || invoice.ExtendedNotifications;
|
|
||||||
entity.ExtendedNotifications = invoice.ExtendedNotifications;
|
|
||||||
entity.NotificationURLTemplate = invoice.NotificationURL;
|
|
||||||
entity.NotificationEmail = invoice.NotificationEmail;
|
|
||||||
if (additionalTags != null)
|
|
||||||
entity.InternalTags.AddRange(additionalTags);
|
|
||||||
FillBuyerInfo(invoice, entity);
|
|
||||||
|
|
||||||
var taxIncluded = invoice.TaxIncluded.HasValue ? invoice.TaxIncluded.Value : 0m;
|
|
||||||
var price = invoice.Price;
|
|
||||||
|
|
||||||
entity.Metadata.ItemCode = invoice.ItemCode;
|
|
||||||
entity.Metadata.ItemDesc = invoice.ItemDesc;
|
|
||||||
entity.Metadata.Physical = invoice.Physical;
|
|
||||||
entity.Metadata.TaxIncluded = invoice.TaxIncluded;
|
|
||||||
entity.Currency = invoice.Currency;
|
|
||||||
if (price is decimal vv)
|
|
||||||
{
|
|
||||||
entity.Price = vv;
|
|
||||||
entity.Type = InvoiceType.Standard;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entity.Price = 0m;
|
|
||||||
entity.Type = InvoiceType.TopUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.StoreSupportUrl = storeBlob.StoreSupportUrl;
|
|
||||||
entity.RedirectURLTemplate = invoice.RedirectURL ?? store.StoreWebsite;
|
|
||||||
entity.RedirectAutomatically =
|
|
||||||
invoice.RedirectAutomatically.GetValueOrDefault(storeBlob.RedirectAutomatically);
|
|
||||||
entity.RequiresRefundEmail = invoice.RequiresRefundEmail;
|
|
||||||
entity.SpeedPolicy = ParseSpeedPolicy(invoice.TransactionSpeed, store.SpeedPolicy);
|
|
||||||
|
|
||||||
IPaymentFilter? excludeFilter = null;
|
|
||||||
if (invoice.PaymentCurrencies?.Any() is true)
|
|
||||||
{
|
|
||||||
invoice.SupportedTransactionCurrencies ??=
|
|
||||||
new Dictionary<string, InvoiceSupportedTransactionCurrency>();
|
|
||||||
foreach (string paymentCurrency in invoice.PaymentCurrencies)
|
|
||||||
{
|
|
||||||
invoice.SupportedTransactionCurrencies.TryAdd(paymentCurrency,
|
|
||||||
new InvoiceSupportedTransactionCurrency() { Enabled = true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (invoice.SupportedTransactionCurrencies != null && invoice.SupportedTransactionCurrencies.Count != 0)
|
|
||||||
{
|
|
||||||
var supportedTransactionCurrencies = invoice.SupportedTransactionCurrencies
|
|
||||||
.Where(c => c.Value.Enabled)
|
|
||||||
.Select(c => PaymentMethodId.TryParse(c.Key, out var p) ? p : null)
|
|
||||||
.Where(c => c != null)
|
|
||||||
.ToHashSet();
|
|
||||||
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
|
|
||||||
}
|
|
||||||
entity.PaymentTolerance = storeBlob.PaymentTolerance;
|
|
||||||
entity.DefaultPaymentMethod = invoice.DefaultPaymentMethod;
|
|
||||||
entity.RequiresRefundEmail = invoice.RequiresRefundEmail;
|
|
||||||
|
|
||||||
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, null, cancellationToken, entityManipulator);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal async Task<InvoiceEntity> CreatePaymentRequestInvoice(Data.PaymentRequestData prData, decimal? amount, decimal amountDue, StoreData storeData, HttpRequest request, CancellationToken cancellationToken)
|
internal async Task<InvoiceEntity> CreatePaymentRequestInvoice(Data.PaymentRequestData prData, decimal? amount, decimal amountDue, StoreData storeData, HttpRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var id = prData.Id;
|
var id = prData.Id;
|
||||||
@@ -548,45 +451,5 @@ namespace BTCPayServer.Controllers
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SpeedPolicy ParseSpeedPolicy(string transactionSpeed, SpeedPolicy defaultPolicy)
|
|
||||||
{
|
|
||||||
if (transactionSpeed == null)
|
|
||||||
return defaultPolicy;
|
|
||||||
var mappings = new Dictionary<string, SpeedPolicy>();
|
|
||||||
mappings.Add("low", SpeedPolicy.LowSpeed);
|
|
||||||
mappings.Add("low-medium", SpeedPolicy.LowMediumSpeed);
|
|
||||||
mappings.Add("medium", SpeedPolicy.MediumSpeed);
|
|
||||||
mappings.Add("high", SpeedPolicy.HighSpeed);
|
|
||||||
if (!mappings.TryGetValue(transactionSpeed, out SpeedPolicy policy))
|
|
||||||
policy = defaultPolicy;
|
|
||||||
return policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FillBuyerInfo(BitpayCreateInvoiceRequest req, InvoiceEntity invoiceEntity)
|
|
||||||
{
|
|
||||||
var buyerInformation = invoiceEntity.Metadata;
|
|
||||||
buyerInformation.BuyerAddress1 = req.BuyerAddress1;
|
|
||||||
buyerInformation.BuyerAddress2 = req.BuyerAddress2;
|
|
||||||
buyerInformation.BuyerCity = req.BuyerCity;
|
|
||||||
buyerInformation.BuyerCountry = req.BuyerCountry;
|
|
||||||
buyerInformation.BuyerEmail = req.BuyerEmail;
|
|
||||||
buyerInformation.BuyerName = req.BuyerName;
|
|
||||||
buyerInformation.BuyerPhone = req.BuyerPhone;
|
|
||||||
buyerInformation.BuyerState = req.BuyerState;
|
|
||||||
buyerInformation.BuyerZip = req.BuyerZip;
|
|
||||||
var buyer = req.Buyer;
|
|
||||||
if (buyer == null)
|
|
||||||
return;
|
|
||||||
buyerInformation.BuyerAddress1 ??= buyer.Address1;
|
|
||||||
buyerInformation.BuyerAddress2 ??= buyer.Address2;
|
|
||||||
buyerInformation.BuyerCity ??= buyer.City;
|
|
||||||
buyerInformation.BuyerCountry ??= buyer.country;
|
|
||||||
buyerInformation.BuyerEmail ??= buyer.email;
|
|
||||||
buyerInformation.BuyerName ??= buyer.Name;
|
|
||||||
buyerInformation.BuyerPhone ??= buyer.phone;
|
|
||||||
buyerInformation.BuyerState ??= buyer.State;
|
|
||||||
buyerInformation.BuyerZip ??= buyer.zip;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,16 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using BTCPayServer.Abstractions.Extensions;
|
using BTCPayServer.Abstractions.Extensions;
|
||||||
|
using BTCPayServer.Client.Models;
|
||||||
|
using BTCPayServer.Controllers.Greenfield;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Plugins.PayButton.Models;
|
using BTCPayServer.Plugins.PayButton.Models;
|
||||||
|
using BTCPayServer.Services.Invoices;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
using Microsoft.AspNetCore.Cors;
|
using Microsoft.AspNetCore.Cors;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
using NicolasDorier.RateLimits;
|
using NicolasDorier.RateLimits;
|
||||||
|
|
||||||
namespace BTCPayServer.Controllers
|
namespace BTCPayServer.Controllers
|
||||||
@@ -16,14 +20,17 @@ namespace BTCPayServer.Controllers
|
|||||||
public class UIPublicController : Controller
|
public class UIPublicController : Controller
|
||||||
{
|
{
|
||||||
public UIPublicController(UIInvoiceController invoiceController,
|
public UIPublicController(UIInvoiceController invoiceController,
|
||||||
StoreRepository storeRepository)
|
StoreRepository storeRepository,
|
||||||
|
LinkGenerator linkGenerator)
|
||||||
{
|
{
|
||||||
_InvoiceController = invoiceController;
|
_InvoiceController = invoiceController;
|
||||||
_StoreRepository = storeRepository;
|
_StoreRepository = storeRepository;
|
||||||
|
_linkGenerator = linkGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly UIInvoiceController _InvoiceController;
|
private readonly UIInvoiceController _InvoiceController;
|
||||||
private readonly StoreRepository _StoreRepository;
|
private readonly StoreRepository _StoreRepository;
|
||||||
|
private readonly LinkGenerator _linkGenerator;
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[IgnoreAntiforgeryToken]
|
[IgnoreAntiforgeryToken]
|
||||||
@@ -57,21 +64,31 @@ namespace BTCPayServer.Controllers
|
|||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
return View();
|
return View();
|
||||||
|
|
||||||
DataWrapper<InvoiceResponse> invoice = null;
|
InvoiceEntity invoice = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
invoice = await _InvoiceController.CreateInvoiceCore(new BitpayCreateInvoiceRequest()
|
invoice = await _InvoiceController.CreateInvoiceCoreRaw(new CreateInvoiceRequest()
|
||||||
{
|
{
|
||||||
Price = model.Price,
|
Amount = model.Price,
|
||||||
Currency = model.Currency,
|
Currency = model.Currency,
|
||||||
ItemDesc = model.CheckoutDesc,
|
Metadata = new InvoiceMetadata()
|
||||||
OrderId = model.OrderId,
|
{
|
||||||
NotificationEmail = model.NotifyEmail,
|
ItemDesc = model.CheckoutDesc,
|
||||||
NotificationURL = model.ServerIpn,
|
OrderId = model.OrderId
|
||||||
RedirectURL = model.BrowserRedirect,
|
}.ToJObject(),
|
||||||
FullNotifications = true,
|
Checkout = new ()
|
||||||
DefaultPaymentMethod = model.DefaultPaymentMethod
|
{
|
||||||
}, store, HttpContext.Request.GetAbsoluteRoot(), cancellationToken: cancellationToken);
|
RedirectURL = model.BrowserRedirect ?? store?.StoreWebsite,
|
||||||
|
DefaultPaymentMethod = model.DefaultPaymentMethod
|
||||||
|
}
|
||||||
|
}, store, HttpContext.Request.GetAbsoluteRoot(),
|
||||||
|
entityManipulator: (entity) =>
|
||||||
|
{
|
||||||
|
entity.NotificationEmail = model.NotifyEmail;
|
||||||
|
entity.NotificationURLTemplate = model.ServerIpn;
|
||||||
|
entity.FullNotifications = true;
|
||||||
|
},
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
catch (BitpayHttpException e)
|
catch (BitpayHttpException e)
|
||||||
{
|
{
|
||||||
@@ -84,26 +101,25 @@ namespace BTCPayServer.Controllers
|
|||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var url = GreenfieldInvoiceController.ToModel(invoice, _linkGenerator, HttpContext.Request).CheckoutLink;
|
||||||
|
if (!string.IsNullOrEmpty(model.CheckoutQueryString))
|
||||||
|
{
|
||||||
|
var additionalParamValues = HttpUtility.ParseQueryString(model.CheckoutQueryString);
|
||||||
|
var uriBuilder = new UriBuilder(url);
|
||||||
|
var paramValues = HttpUtility.ParseQueryString(uriBuilder.Query);
|
||||||
|
paramValues.Add(additionalParamValues);
|
||||||
|
uriBuilder.Query = paramValues.ToString()!;
|
||||||
|
url = uriBuilder.Uri.AbsoluteUri;
|
||||||
|
}
|
||||||
if (model.JsonResponse)
|
if (model.JsonResponse)
|
||||||
{
|
{
|
||||||
return Json(new
|
return Json(new
|
||||||
{
|
{
|
||||||
InvoiceId = invoice.Data.Id,
|
InvoiceId = invoice.Id,
|
||||||
InvoiceUrl = invoice.Data.Url
|
InvoiceUrl = url
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return Redirect(url);
|
||||||
if (string.IsNullOrEmpty(model.CheckoutQueryString))
|
|
||||||
{
|
|
||||||
return Redirect(invoice.Data.Url);
|
|
||||||
}
|
|
||||||
|
|
||||||
var additionalParamValues = HttpUtility.ParseQueryString(model.CheckoutQueryString);
|
|
||||||
var uriBuilder = new UriBuilder(invoice.Data.Url);
|
|
||||||
var paramValues = HttpUtility.ParseQueryString(uriBuilder.Query);
|
|
||||||
paramValues.Add(additionalParamValues);
|
|
||||||
uriBuilder.Query = paramValues.ToString();
|
|
||||||
return Redirect(uriBuilder.Uri.AbsoluteUri);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user