mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Greenfield: add text search terms to an invoice (#2648)
This commit is contained in:
@@ -14,6 +14,7 @@ namespace BTCPayServer.Client
|
|||||||
public virtual async Task<IEnumerable<InvoiceData>> GetInvoices(string storeId, string orderId = null, InvoiceStatus[] status = null,
|
public virtual async Task<IEnumerable<InvoiceData>> GetInvoices(string storeId, string orderId = null, InvoiceStatus[] status = null,
|
||||||
DateTimeOffset? startDate = null,
|
DateTimeOffset? startDate = null,
|
||||||
DateTimeOffset? endDate = null,
|
DateTimeOffset? endDate = null,
|
||||||
|
string textSearch = null,
|
||||||
bool includeArchived = false,
|
bool includeArchived = false,
|
||||||
CancellationToken token = default)
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
@@ -28,7 +29,8 @@ namespace BTCPayServer.Client
|
|||||||
|
|
||||||
if (orderId != null)
|
if (orderId != null)
|
||||||
queryPayload.Add(nameof(orderId), orderId);
|
queryPayload.Add(nameof(orderId), orderId);
|
||||||
|
if (textSearch != null)
|
||||||
|
queryPayload.Add(nameof(textSearch), textSearch);
|
||||||
if (status != null)
|
if (status != null)
|
||||||
queryPayload.Add(nameof(status), status.Select(s=> s.ToString().ToLower()).ToArray());
|
queryPayload.Add(nameof(status), status.Select(s=> s.ToString().ToLower()).ToArray());
|
||||||
|
|
||||||
|
|||||||
@@ -7,35 +7,8 @@ using Newtonsoft.Json.Linq;
|
|||||||
|
|
||||||
namespace BTCPayServer.Client.Models
|
namespace BTCPayServer.Client.Models
|
||||||
{
|
{
|
||||||
public class CreateInvoiceRequest
|
public class CreateInvoiceRequest : InvoiceDataBase
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(NumericStringJsonConverter))]
|
public string[] AdditionalSearchTerms { get; set; }
|
||||||
public decimal Amount { get; set; }
|
|
||||||
public string Currency { get; set; }
|
|
||||||
public JObject Metadata { get; set; }
|
|
||||||
public CheckoutOptions Checkout { get; set; } = new CheckoutOptions();
|
|
||||||
|
|
||||||
public class CheckoutOptions
|
|
||||||
{
|
|
||||||
|
|
||||||
[JsonConverter(typeof(StringEnumConverter))]
|
|
||||||
public SpeedPolicy? SpeedPolicy { get; set; }
|
|
||||||
|
|
||||||
public string[] PaymentMethods { get; set; }
|
|
||||||
|
|
||||||
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
|
|
||||||
[JsonProperty("expirationMinutes")]
|
|
||||||
public TimeSpan? Expiration { get; set; }
|
|
||||||
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
|
|
||||||
[JsonProperty("monitoringMinutes")]
|
|
||||||
public TimeSpan? Monitoring { get; set; }
|
|
||||||
|
|
||||||
public double? PaymentTolerance { get; set; }
|
|
||||||
[JsonProperty("redirectURL")]
|
|
||||||
public string RedirectURL { get; set; }
|
|
||||||
|
|
||||||
public bool? RedirectAutomatically { get; set; }
|
|
||||||
public string DefaultLanguage { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,43 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using BTCPayServer.Client.JsonConverters;
|
||||||
|
using BTCPayServer.JsonConverters;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace BTCPayServer.Client.Models
|
namespace BTCPayServer.Client.Models
|
||||||
{
|
{
|
||||||
public class InvoiceData : CreateInvoiceRequest
|
public class InvoiceDataBase
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(NumericStringJsonConverter))]
|
||||||
|
public decimal Amount { get; set; }
|
||||||
|
public string Currency { get; set; }
|
||||||
|
public JObject Metadata { get; set; }
|
||||||
|
public CheckoutOptions Checkout { get; set; } = new CheckoutOptions();
|
||||||
|
public class CheckoutOptions
|
||||||
|
{
|
||||||
|
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public SpeedPolicy? SpeedPolicy { get; set; }
|
||||||
|
|
||||||
|
public string[] PaymentMethods { get; set; }
|
||||||
|
|
||||||
|
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
|
||||||
|
[JsonProperty("expirationMinutes")]
|
||||||
|
public TimeSpan? Expiration { get; set; }
|
||||||
|
[JsonConverter(typeof(TimeSpanJsonConverter.Minutes))]
|
||||||
|
[JsonProperty("monitoringMinutes")]
|
||||||
|
public TimeSpan? Monitoring { get; set; }
|
||||||
|
|
||||||
|
public double? PaymentTolerance { get; set; }
|
||||||
|
[JsonProperty("redirectURL")]
|
||||||
|
public string RedirectURL { get; set; }
|
||||||
|
|
||||||
|
public bool? RedirectAutomatically { get; set; }
|
||||||
|
public string DefaultLanguage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class InvoiceData : InvoiceDataBase
|
||||||
{
|
{
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string StoreId { get; set; }
|
public string StoreId { get; set; }
|
||||||
|
|||||||
@@ -1035,10 +1035,17 @@ namespace BTCPayServer.Tests
|
|||||||
});
|
});
|
||||||
await user.RegisterDerivationSchemeAsync("BTC");
|
await user.RegisterDerivationSchemeAsync("BTC");
|
||||||
var newInvoice = await client.CreateInvoice(user.StoreId,
|
var newInvoice = await client.CreateInvoice(user.StoreId,
|
||||||
new CreateInvoiceRequest() { Currency = "USD", Amount = 1, Metadata = JObject.Parse("{\"itemCode\": \"testitem\", \"orderId\": \"testOrder\"}"), Checkout = new CreateInvoiceRequest.CheckoutOptions()
|
new CreateInvoiceRequest()
|
||||||
|
{
|
||||||
|
Currency = "USD",
|
||||||
|
Amount = 1,
|
||||||
|
Metadata = JObject.Parse("{\"itemCode\": \"testitem\", \"orderId\": \"testOrder\"}"),
|
||||||
|
Checkout = new CreateInvoiceRequest.CheckoutOptions()
|
||||||
{
|
{
|
||||||
RedirectAutomatically = true
|
RedirectAutomatically = true
|
||||||
}});
|
},
|
||||||
|
AdditionalSearchTerms = new string[] { "Banana" }
|
||||||
|
});
|
||||||
Assert.True(newInvoice.Checkout.RedirectAutomatically);
|
Assert.True(newInvoice.Checkout.RedirectAutomatically);
|
||||||
Assert.Equal(user.StoreId, newInvoice.StoreId);
|
Assert.Equal(user.StoreId, newInvoice.StoreId);
|
||||||
//list
|
//list
|
||||||
@@ -1048,6 +1055,15 @@ namespace BTCPayServer.Tests
|
|||||||
Assert.Single(invoices);
|
Assert.Single(invoices);
|
||||||
Assert.Equal(newInvoice.Id, invoices.First().Id);
|
Assert.Equal(newInvoice.Id, invoices.First().Id);
|
||||||
|
|
||||||
|
invoices = await viewOnly.GetInvoices(user.StoreId, textSearch: "Banana");
|
||||||
|
Assert.NotNull(invoices);
|
||||||
|
Assert.Single(invoices);
|
||||||
|
Assert.Equal(newInvoice.Id, invoices.First().Id);
|
||||||
|
|
||||||
|
invoices = await viewOnly.GetInvoices(user.StoreId, textSearch: "apples");
|
||||||
|
Assert.NotNull(invoices);
|
||||||
|
Assert.Empty(invoices);
|
||||||
|
|
||||||
//list Filtered
|
//list Filtered
|
||||||
var invoicesFiltered = await viewOnly.GetInvoices(user.StoreId,
|
var invoicesFiltered = await viewOnly.GetInvoices(user.StoreId,
|
||||||
orderId: null, status: null, DateTimeOffset.Now.AddHours(-1),
|
orderId: null, status: null, DateTimeOffset.Now.AddHours(-1),
|
||||||
@@ -1092,14 +1108,14 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
//list Existing Status
|
//list Existing Status
|
||||||
var invoicesExistingStatus =
|
var invoicesExistingStatus =
|
||||||
await viewOnly.GetInvoices(user.StoreId, status:new []{newInvoice.Status});
|
await viewOnly.GetInvoices(user.StoreId, status: new[] { newInvoice.Status });
|
||||||
Assert.NotNull(invoicesExistingStatus);
|
Assert.NotNull(invoicesExistingStatus);
|
||||||
Assert.Single(invoicesExistingStatus);
|
Assert.Single(invoicesExistingStatus);
|
||||||
Assert.Equal(newInvoice.Id, invoicesExistingStatus.First().Id);
|
Assert.Equal(newInvoice.Id, invoicesExistingStatus.First().Id);
|
||||||
|
|
||||||
//list NonExisting Status
|
//list NonExisting Status
|
||||||
var invoicesNonExistingStatus = await viewOnly.GetInvoices(user.StoreId,
|
var invoicesNonExistingStatus = await viewOnly.GetInvoices(user.StoreId,
|
||||||
status: new []{BTCPayServer.Client.Models.InvoiceStatus.Invalid});
|
status: new[] { BTCPayServer.Client.Models.InvoiceStatus.Invalid });
|
||||||
Assert.NotNull(invoicesNonExistingStatus);
|
Assert.NotNull(invoicesNonExistingStatus);
|
||||||
Assert.Empty(invoicesNonExistingStatus);
|
Assert.Empty(invoicesNonExistingStatus);
|
||||||
|
|
||||||
@@ -1142,13 +1158,13 @@ namespace BTCPayServer.Tests
|
|||||||
Metadata = JObject.Parse("{\"itemCode\": \"updated\", newstuff: [1,2,3,4,5]}")
|
Metadata = JObject.Parse("{\"itemCode\": \"updated\", newstuff: [1,2,3,4,5]}")
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Equal("updated",invoice.Metadata["itemCode"].Value<string>());
|
Assert.Equal("updated", invoice.Metadata["itemCode"].Value<string>());
|
||||||
Assert.Equal(15,((JArray) invoice.Metadata["newstuff"]).Values<int>().Sum());
|
Assert.Equal(15, ((JArray)invoice.Metadata["newstuff"]).Values<int>().Sum());
|
||||||
|
|
||||||
//also test the the metadata actually got saved
|
//also test the the metadata actually got saved
|
||||||
invoice = await client.GetInvoice(user.StoreId, invoice.Id);
|
invoice = await client.GetInvoice(user.StoreId, invoice.Id);
|
||||||
Assert.Equal("updated",invoice.Metadata["itemCode"].Value<string>());
|
Assert.Equal("updated", invoice.Metadata["itemCode"].Value<string>());
|
||||||
Assert.Equal(15,((JArray) invoice.Metadata["newstuff"]).Values<int>().Sum());
|
Assert.Equal(15, ((JArray)invoice.Metadata["newstuff"]).Values<int>().Sum());
|
||||||
|
|
||||||
//archive
|
//archive
|
||||||
await AssertHttpError(403, async () =>
|
await AssertHttpError(403, async () =>
|
||||||
@@ -1242,7 +1258,7 @@ namespace BTCPayServer.Tests
|
|||||||
JObject.FromObject(store).ToObject<UpdateStoreRequest>());
|
JObject.FromObject(store).ToObject<UpdateStoreRequest>());
|
||||||
Assert.True(store.LazyPaymentMethods);
|
Assert.True(store.LazyPaymentMethods);
|
||||||
|
|
||||||
invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest() {Amount = 1, Currency = "USD"});
|
invoice = await client.CreateInvoice(user.StoreId, new CreateInvoiceRequest() { Amount = 1, Currency = "USD" });
|
||||||
paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id);
|
paymentMethods = await client.GetInvoicePaymentMethods(store.Id, invoice.Id);
|
||||||
Assert.Single(paymentMethods);
|
Assert.Single(paymentMethods);
|
||||||
Assert.False(paymentMethods.First().Activated);
|
Assert.False(paymentMethods.First().Activated);
|
||||||
@@ -1393,7 +1409,7 @@ namespace BTCPayServer.Tests
|
|||||||
var client = await user.CreateClient(Policies.CanModifyStoreSettings);
|
var client = await user.CreateClient(Policies.CanModifyStoreSettings);
|
||||||
var viewOnlyClient = await user.CreateClient(Policies.CanViewStoreSettings);
|
var viewOnlyClient = await user.CreateClient(Policies.CanViewStoreSettings);
|
||||||
|
|
||||||
var store = await client.CreateStore(new CreateStoreRequest() {Name = "test store"});
|
var store = await client.CreateStore(new CreateStoreRequest() { Name = "test store" });
|
||||||
|
|
||||||
Assert.Empty(await client.GetStoreOnChainPaymentMethods(store.Id));
|
Assert.Empty(await client.GetStoreOnChainPaymentMethods(store.Id));
|
||||||
await AssertHttpError(403, async () =>
|
await AssertHttpError(403, async () =>
|
||||||
@@ -1410,12 +1426,12 @@ namespace BTCPayServer.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
Assert.Equal(firstAddress, (await viewOnlyClient.PreviewProposedStoreOnChainPaymentMethodAddresses(store.Id, "BTC",
|
Assert.Equal(firstAddress, (await viewOnlyClient.PreviewProposedStoreOnChainPaymentMethodAddresses(store.Id, "BTC",
|
||||||
new OnChainPaymentMethodData() {Enabled = true, DerivationScheme = xpub})).Addresses.First().Address);
|
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub })).Addresses.First().Address);
|
||||||
|
|
||||||
var method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC",
|
var method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC",
|
||||||
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub});
|
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub });
|
||||||
|
|
||||||
Assert.Equal(xpub,method.DerivationScheme);
|
Assert.Equal(xpub, method.DerivationScheme);
|
||||||
|
|
||||||
method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC",
|
method = await client.UpdateStoreOnChainPaymentMethod(store.Id, "BTC",
|
||||||
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub, Label = "lol", AccountKeyPath = RootedKeyPath.Parse("01020304/1/2/3") });
|
new OnChainPaymentMethodData() { Enabled = true, DerivationScheme = xpub, Label = "lol", AccountKeyPath = RootedKeyPath.Parse("01020304/1/2/3") });
|
||||||
@@ -1424,7 +1440,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
Assert.Equal("lol", method.Label);
|
Assert.Equal("lol", method.Label);
|
||||||
Assert.Equal(RootedKeyPath.Parse("01020304/1/2/3"), method.AccountKeyPath);
|
Assert.Equal(RootedKeyPath.Parse("01020304/1/2/3"), method.AccountKeyPath);
|
||||||
Assert.Equal(xpub,method.DerivationScheme);
|
Assert.Equal(xpub, method.DerivationScheme);
|
||||||
|
|
||||||
|
|
||||||
Assert.Equal(firstAddress, (await viewOnlyClient.PreviewStoreOnChainPaymentMethodAddresses(store.Id, "BTC")).Addresses.First().Address);
|
Assert.Equal(firstAddress, (await viewOnlyClient.PreviewStoreOnChainPaymentMethodAddresses(store.Id, "BTC")).Addresses.First().Address);
|
||||||
@@ -1530,12 +1546,12 @@ namespace BTCPayServer.Tests
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
var settings = (await tester.PayTester.GetService<SettingsRepository>().GetSettingAsync<PoliciesSettings>())?? new PoliciesSettings();
|
var settings = (await tester.PayTester.GetService<SettingsRepository>().GetSettingAsync<PoliciesSettings>()) ?? new PoliciesSettings();
|
||||||
settings.AllowLightningInternalNodeForAll = false;
|
settings.AllowLightningInternalNodeForAll = false;
|
||||||
await tester.PayTester.GetService<SettingsRepository>().UpdateSetting(settings);
|
await tester.PayTester.GetService<SettingsRepository>().UpdateSetting(settings);
|
||||||
var nonAdminUser = tester.NewAccount();
|
var nonAdminUser = tester.NewAccount();
|
||||||
await nonAdminUser.GrantAccessAsync(false);
|
await nonAdminUser.GrantAccessAsync(false);
|
||||||
var nonAdminUserClient= await nonAdminUser.CreateClient(Policies.CanModifyStoreSettings);
|
var nonAdminUserClient = await nonAdminUser.CreateClient(Policies.CanModifyStoreSettings);
|
||||||
|
|
||||||
await AssertHttpError(404, async () =>
|
await AssertHttpError(404, async () =>
|
||||||
{
|
{
|
||||||
@@ -1570,22 +1586,22 @@ namespace BTCPayServer.Tests
|
|||||||
//view only clients can't do jack shit with this API
|
//view only clients can't do jack shit with this API
|
||||||
await AssertHttpError(403, async () =>
|
await AssertHttpError(403, async () =>
|
||||||
{
|
{
|
||||||
await viewOnlyClient.ShowOnChainWalletOverview(walletId.StoreId, walletId.CryptoCode );
|
await viewOnlyClient.ShowOnChainWalletOverview(walletId.StoreId, walletId.CryptoCode);
|
||||||
});
|
});
|
||||||
var overview = await client.ShowOnChainWalletOverview(walletId.StoreId, walletId.CryptoCode );
|
var overview = await client.ShowOnChainWalletOverview(walletId.StoreId, walletId.CryptoCode);
|
||||||
Assert.Equal(0m, overview.Balance);
|
Assert.Equal(0m, overview.Balance);
|
||||||
|
|
||||||
|
|
||||||
var fee = await client.GetOnChainFeeRate(walletId.StoreId, walletId.CryptoCode );
|
var fee = await client.GetOnChainFeeRate(walletId.StoreId, walletId.CryptoCode);
|
||||||
Assert.NotNull( fee.FeeRate);
|
Assert.NotNull(fee.FeeRate);
|
||||||
|
|
||||||
await AssertHttpError(403, async () =>
|
await AssertHttpError(403, async () =>
|
||||||
{
|
{
|
||||||
await viewOnlyClient.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode );
|
await viewOnlyClient.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode);
|
||||||
});
|
});
|
||||||
var address = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode );
|
var address = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode);
|
||||||
var address2 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode );
|
var address2 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode);
|
||||||
var address3 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode, true );
|
var address3 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode, true);
|
||||||
Assert.Equal(address.Address, address2.Address);
|
Assert.Equal(address.Address, address2.Address);
|
||||||
Assert.NotEqual(address.Address, address3.Address);
|
Assert.NotEqual(address.Address, address3.Address);
|
||||||
await AssertHttpError(403, async () =>
|
await AssertHttpError(403, async () =>
|
||||||
@@ -1602,17 +1618,17 @@ namespace BTCPayServer.Tests
|
|||||||
});
|
});
|
||||||
await tester.ExplorerNode.GenerateAsync(1);
|
await tester.ExplorerNode.GenerateAsync(1);
|
||||||
|
|
||||||
var address4 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode, false );
|
var address4 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode, false);
|
||||||
Assert.NotEqual(address3.Address, address4.Address);
|
Assert.NotEqual(address3.Address, address4.Address);
|
||||||
await client.UnReserveOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode);
|
await client.UnReserveOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode);
|
||||||
var address5 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode, true );
|
var address5 = await client.GetOnChainWalletReceiveAddress(walletId.StoreId, walletId.CryptoCode, true);
|
||||||
Assert.Equal(address5.Address, address4.Address);
|
Assert.Equal(address5.Address, address4.Address);
|
||||||
|
|
||||||
|
|
||||||
var utxo = Assert.Single(await client.GetOnChainWalletUTXOs(walletId.StoreId, walletId.CryptoCode));
|
var utxo = Assert.Single(await client.GetOnChainWalletUTXOs(walletId.StoreId, walletId.CryptoCode));
|
||||||
Assert.Equal(0.01m, utxo.Amount);
|
Assert.Equal(0.01m, utxo.Amount);
|
||||||
Assert.Equal(txhash, utxo.Outpoint.Hash);
|
Assert.Equal(txhash, utxo.Outpoint.Hash);
|
||||||
overview = await client.ShowOnChainWalletOverview(walletId.StoreId, walletId.CryptoCode );
|
overview = await client.ShowOnChainWalletOverview(walletId.StoreId, walletId.CryptoCode);
|
||||||
Assert.Equal(0.01m, overview.Balance);
|
Assert.Equal(0.01m, overview.Balance);
|
||||||
|
|
||||||
//the simplest request:
|
//the simplest request:
|
||||||
@@ -1631,7 +1647,7 @@ namespace BTCPayServer.Tests
|
|||||||
};
|
};
|
||||||
await AssertHttpError(403, async () =>
|
await AssertHttpError(403, async () =>
|
||||||
{
|
{
|
||||||
await viewOnlyClient.CreateOnChainTransaction(walletId.StoreId, walletId.CryptoCode, createTxRequest );
|
await viewOnlyClient.CreateOnChainTransaction(walletId.StoreId, walletId.CryptoCode, createTxRequest);
|
||||||
});
|
});
|
||||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () =>
|
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(async () =>
|
||||||
{
|
{
|
||||||
@@ -1659,12 +1675,12 @@ namespace BTCPayServer.Tests
|
|||||||
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
||||||
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
||||||
Assert.NotNull(tx);
|
Assert.NotNull(tx);
|
||||||
Assert.True(Assert.Single(tx.Outputs).IsTo(nodeAddress) );
|
Assert.True(Assert.Single(tx.Outputs).IsTo(nodeAddress));
|
||||||
Assert.True((await tester.ExplorerNode.TestMempoolAcceptAsync(tx)).IsAllowed);
|
Assert.True((await tester.ExplorerNode.TestMempoolAcceptAsync(tx)).IsAllowed);
|
||||||
|
|
||||||
createTxRequest.NoChange = false;
|
createTxRequest.NoChange = false;
|
||||||
//coin selection
|
//coin selection
|
||||||
await AssertValidationError(new []{nameof(createTxRequest.SelectedInputs)}, async () =>
|
await AssertValidationError(new[] { nameof(createTxRequest.SelectedInputs) }, async () =>
|
||||||
{
|
{
|
||||||
createTxRequest.SelectedInputs = new List<OutPoint>();
|
createTxRequest.SelectedInputs = new List<OutPoint>();
|
||||||
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
||||||
@@ -1679,7 +1695,7 @@ namespace BTCPayServer.Tests
|
|||||||
createTxRequest.SelectedInputs = null;
|
createTxRequest.SelectedInputs = null;
|
||||||
|
|
||||||
//destination testing
|
//destination testing
|
||||||
await AssertValidationError(new []{ "Destinations"}, async () =>
|
await AssertValidationError(new[] { "Destinations" }, async () =>
|
||||||
{
|
{
|
||||||
createTxRequest.Destinations[0].Amount = utxo.Amount;
|
createTxRequest.Destinations[0].Amount = utxo.Amount;
|
||||||
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
||||||
@@ -1691,7 +1707,7 @@ namespace BTCPayServer.Tests
|
|||||||
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
||||||
|
|
||||||
|
|
||||||
await AssertValidationError(new []{ "Destinations[0]"}, async () =>
|
await AssertValidationError(new[] { "Destinations[0]" }, async () =>
|
||||||
{
|
{
|
||||||
createTxRequest.Destinations[0].Amount = 0m;
|
createTxRequest.Destinations[0].Amount = 0m;
|
||||||
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
||||||
@@ -1703,7 +1719,7 @@ namespace BTCPayServer.Tests
|
|||||||
//cant use bip with subtractfromamount
|
//cant use bip with subtractfromamount
|
||||||
createTxRequest.Destinations[0].Amount = null;
|
createTxRequest.Destinations[0].Amount = null;
|
||||||
createTxRequest.Destinations[0].Destination = $"bitcoin:{nodeAddress}?amount=0.001";
|
createTxRequest.Destinations[0].Destination = $"bitcoin:{nodeAddress}?amount=0.001";
|
||||||
await AssertValidationError(new []{ "Destinations[0]"}, async () =>
|
await AssertValidationError(new[] { "Destinations[0]" }, async () =>
|
||||||
{
|
{
|
||||||
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
||||||
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
||||||
@@ -1713,11 +1729,11 @@ namespace BTCPayServer.Tests
|
|||||||
createTxRequest.Destinations[0].SubtractFromAmount = false;
|
createTxRequest.Destinations[0].SubtractFromAmount = false;
|
||||||
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
||||||
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
||||||
Assert.Contains(tx.Outputs, txout => txout.Value.GetValue(tester.NetworkProvider.GetNetwork<BTCPayNetwork>("BTC")) ==0.0001m );
|
Assert.Contains(tx.Outputs, txout => txout.Value.GetValue(tester.NetworkProvider.GetNetwork<BTCPayNetwork>("BTC")) == 0.0001m);
|
||||||
|
|
||||||
//fee rate test
|
//fee rate test
|
||||||
createTxRequest.FeeRate = FeeRate.Zero;
|
createTxRequest.FeeRate = FeeRate.Zero;
|
||||||
await AssertValidationError(new []{ "FeeRate"}, async () =>
|
await AssertValidationError(new[] { "FeeRate" }, async () =>
|
||||||
{
|
{
|
||||||
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
tx = await client.CreateOnChainTransactionButDoNotBroadcast(walletId.StoreId, walletId.CryptoCode,
|
||||||
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
||||||
@@ -1735,7 +1751,7 @@ namespace BTCPayServer.Tests
|
|||||||
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
createTxRequest, tester.ExplorerClient.Network.NBitcoinNetwork);
|
||||||
});
|
});
|
||||||
createTxRequest.ProceedWithBroadcast = true;
|
createTxRequest.ProceedWithBroadcast = true;
|
||||||
var txdata=
|
var txdata =
|
||||||
await client.CreateOnChainTransaction(walletId.StoreId, walletId.CryptoCode,
|
await client.CreateOnChainTransaction(walletId.StoreId, walletId.CryptoCode,
|
||||||
createTxRequest);
|
createTxRequest);
|
||||||
Assert.Equal(TransactionStatus.Unconfirmed, txdata.Status);
|
Assert.Equal(TransactionStatus.Unconfirmed, txdata.Status);
|
||||||
@@ -1755,10 +1771,10 @@ namespace BTCPayServer.Tests
|
|||||||
});
|
});
|
||||||
Assert.True(Assert.Single(
|
Assert.True(Assert.Single(
|
||||||
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode,
|
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode,
|
||||||
new[] {TransactionStatus.Confirmed})).TransactionHash == utxo.Outpoint.Hash);
|
new[] { TransactionStatus.Confirmed })).TransactionHash == utxo.Outpoint.Hash);
|
||||||
Assert.Contains(
|
Assert.Contains(
|
||||||
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode,
|
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode,
|
||||||
new[] {TransactionStatus.Unconfirmed}), data => data.TransactionHash == txdata.TransactionHash);
|
new[] { TransactionStatus.Unconfirmed }), data => data.TransactionHash == txdata.TransactionHash);
|
||||||
Assert.Contains(
|
Assert.Contains(
|
||||||
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode), data => data.TransactionHash == txdata.TransactionHash);
|
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode), data => data.TransactionHash == txdata.TransactionHash);
|
||||||
await tester.WaitForEvent<NewBlockEvent>(async () =>
|
await tester.WaitForEvent<NewBlockEvent>(async () =>
|
||||||
@@ -1769,7 +1785,7 @@ namespace BTCPayServer.Tests
|
|||||||
|
|
||||||
Assert.Contains(
|
Assert.Contains(
|
||||||
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode,
|
await client.ShowOnChainWalletTransactions(walletId.StoreId, walletId.CryptoCode,
|
||||||
new[] {TransactionStatus.Confirmed}), data => data.TransactionHash == txdata.TransactionHash);
|
new[] { TransactionStatus.Confirmed }), data => data.TransactionHash == txdata.TransactionHash);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ namespace BTCPayServer.Controllers.GreenField
|
|||||||
DateTimeOffset? startDate = null,
|
DateTimeOffset? startDate = null,
|
||||||
[FromQuery]
|
[FromQuery]
|
||||||
[ModelBinder(typeof(ModelBinders.DateTimeOffsetModelBinder))]
|
[ModelBinder(typeof(ModelBinders.DateTimeOffsetModelBinder))]
|
||||||
DateTimeOffset? endDate = null, [FromQuery] bool includeArchived = false)
|
DateTimeOffset? endDate = null,
|
||||||
|
string textSearch = null,
|
||||||
|
[FromQuery] bool includeArchived = false)
|
||||||
{
|
{
|
||||||
var store = HttpContext.GetStoreData();
|
var store = HttpContext.GetStoreData();
|
||||||
if (store == null)
|
if (store == null)
|
||||||
@@ -79,7 +81,8 @@ namespace BTCPayServer.Controllers.GreenField
|
|||||||
StartDate = startDate,
|
StartDate = startDate,
|
||||||
EndDate = endDate,
|
EndDate = endDate,
|
||||||
OrderId = orderId,
|
OrderId = orderId,
|
||||||
Status = status
|
Status = status,
|
||||||
|
TextSearch = textSearch
|
||||||
});
|
});
|
||||||
|
|
||||||
return Ok(invoices.Select(ToModel));
|
return Ok(invoices.Select(ToModel));
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ namespace BTCPayServer.Controllers
|
|||||||
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
|
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
|
||||||
}
|
}
|
||||||
entity.PaymentTolerance = storeBlob.PaymentTolerance;
|
entity.PaymentTolerance = storeBlob.PaymentTolerance;
|
||||||
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, cancellationToken);
|
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, null, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null, CancellationToken cancellationToken = default)
|
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(CreateInvoiceRequest invoice, StoreData store, string serverUrl, List<string> additionalTags = null, CancellationToken cancellationToken = default)
|
||||||
@@ -183,10 +183,10 @@ namespace BTCPayServer.Controllers
|
|||||||
entity.RedirectURLTemplate = invoice.Checkout.RedirectURL?.Trim();
|
entity.RedirectURLTemplate = invoice.Checkout.RedirectURL?.Trim();
|
||||||
if (additionalTags != null)
|
if (additionalTags != null)
|
||||||
entity.InternalTags.AddRange(additionalTags);
|
entity.InternalTags.AddRange(additionalTags);
|
||||||
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, cancellationToken);
|
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, invoice.AdditionalSearchTerms, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter invoicePaymentMethodFilter, CancellationToken cancellationToken = default)
|
internal async Task<InvoiceEntity> CreateInvoiceCoreRaw(InvoiceEntity entity, StoreData store, IPaymentFilter invoicePaymentMethodFilter, string[] additionalSearchTerms = null, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
InvoiceLogs logs = new InvoiceLogs();
|
InvoiceLogs logs = new InvoiceLogs();
|
||||||
logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info);
|
logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info);
|
||||||
@@ -273,7 +273,7 @@ namespace BTCPayServer.Controllers
|
|||||||
|
|
||||||
using (logs.Measure("Saving invoice"))
|
using (logs.Measure("Saving invoice"))
|
||||||
{
|
{
|
||||||
entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity);
|
entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, additionalSearchTerms);
|
||||||
}
|
}
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -148,9 +148,9 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<InvoiceEntity> CreateInvoiceAsync(string storeId, InvoiceEntity invoice)
|
public async Task<InvoiceEntity> CreateInvoiceAsync(string storeId, InvoiceEntity invoice, string[] additionalSearchTerms = null)
|
||||||
{
|
{
|
||||||
var textSearch = new List<string>();
|
var textSearch = new HashSet<string>();
|
||||||
invoice = Clone(invoice);
|
invoice = Clone(invoice);
|
||||||
invoice.Networks = _Networks;
|
invoice.Networks = _Networks;
|
||||||
invoice.Id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(16));
|
invoice.Id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(16));
|
||||||
@@ -210,6 +210,11 @@ namespace BTCPayServer.Services.Invoices
|
|||||||
textSearch.Add(invoice.Metadata.OrderId);
|
textSearch.Add(invoice.Metadata.OrderId);
|
||||||
textSearch.Add(invoice.StoreId);
|
textSearch.Add(invoice.StoreId);
|
||||||
textSearch.Add(invoice.Metadata.BuyerEmail);
|
textSearch.Add(invoice.Metadata.BuyerEmail);
|
||||||
|
|
||||||
|
if (additionalSearchTerms != null)
|
||||||
|
{
|
||||||
|
textSearch.AddRange(additionalSearchTerms);
|
||||||
|
}
|
||||||
AddToTextSearch(context, invoiceData, textSearch.ToArray());
|
AddToTextSearch(context, invoiceData, textSearch.ToArray());
|
||||||
|
|
||||||
await context.SaveChangesAsync().ConfigureAwait(false);
|
await context.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|||||||
@@ -35,6 +35,15 @@
|
|||||||
"description": "Array of statuses of invoices to be fetched",
|
"description": "Array of statuses of invoices to be fetched",
|
||||||
"$ref": "#/components/schemas/InvoiceStatus"
|
"$ref": "#/components/schemas/InvoiceStatus"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "textSearch",
|
||||||
|
"in": "query",
|
||||||
|
"required": false,
|
||||||
|
"description": "A term that can help locating specific invoices.",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "startDate",
|
"name": "startDate",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
@@ -736,10 +745,36 @@
|
|||||||
"PaidOver"
|
"PaidOver"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"InvoiceDataBase": {
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "decimal",
|
||||||
|
"description": "The amount of the invoice"
|
||||||
|
},
|
||||||
|
"currency": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "The currency the invoice will use"
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"$ref": "#/components/schemas/InvoiceMetadata"
|
||||||
|
},
|
||||||
|
"checkout": {
|
||||||
|
"nullable": true,
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/CheckoutOptions"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Additional settings to customize the checkout flow"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"InvoiceData": {
|
"InvoiceData": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
"$ref": "#/components/schemas/CreateInvoiceRequest"
|
"$ref": "#/components/schemas/InvoiceDataBase"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -759,15 +794,15 @@
|
|||||||
},
|
},
|
||||||
"createdTime": {
|
"createdTime": {
|
||||||
"description": "The creation time of the invoice",
|
"description": "The creation time of the invoice",
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}]
|
"allOf": [ { "$ref": "#/components/schemas/UnixTimestamp" } ]
|
||||||
},
|
},
|
||||||
"expirationTime": {
|
"expirationTime": {
|
||||||
"description": "The expiration time of the invoice",
|
"description": "The expiration time of the invoice",
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}]
|
"allOf": [ { "$ref": "#/components/schemas/UnixTimestamp" } ]
|
||||||
},
|
},
|
||||||
"monitoringTime": {
|
"monitoringTime": {
|
||||||
"description": "The monitoring time of the invoice",
|
"description": "The monitoring time of the invoice",
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}]
|
"allOf": [ { "$ref": "#/components/schemas/UnixTimestamp" } ]
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"$ref": "#/components/schemas/InvoiceStatus",
|
"$ref": "#/components/schemas/InvoiceStatus",
|
||||||
@@ -929,32 +964,25 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"CreateInvoiceRequest": {
|
"CreateInvoiceRequest": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/schemas/InvoiceDataBase"
|
||||||
|
},
|
||||||
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"amount": {
|
"additionalSearchTerms": {
|
||||||
"type": "string",
|
"type": "array",
|
||||||
"format": "decimal",
|
"items": {
|
||||||
"description": "The amount of the invoice"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"currency": {
|
"description": "Additional search term to help you find this invoice via text search",
|
||||||
"type": "string",
|
"nullable": true
|
||||||
"nullable": true,
|
|
||||||
"description": "The currency the invoice will use"
|
|
||||||
},
|
|
||||||
"metadata": {
|
|
||||||
"$ref": "#/components/schemas/InvoiceMetadata"
|
|
||||||
},
|
|
||||||
"checkout": {
|
|
||||||
"nullable": true,
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/components/schemas/CheckoutOptions"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Additional settings to customize the checkout flow"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"UpdateInvoiceRequest": {
|
"UpdateInvoiceRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -989,13 +1017,13 @@
|
|||||||
"expirationMinutes": {
|
"expirationMinutes": {
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
"description": "The number of minutes after which an invoice becomes expired. Defaults to the store's settings. (The default store settings is 15)",
|
"description": "The number of minutes after which an invoice becomes expired. Defaults to the store's settings. (The default store settings is 15)",
|
||||||
"allOf": [ {"$ref": "#/components/schemas/TimeSpanMinutes"}]
|
"allOf": [ { "$ref": "#/components/schemas/TimeSpanMinutes" } ]
|
||||||
},
|
},
|
||||||
"monitoringMinutes": {
|
"monitoringMinutes": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
"description": "The number of minutes after an invoice expired after which we are still monitoring for incoming payments. Defaults to the store's settings. (The default store settings is 1440, 1 day)",
|
"description": "The number of minutes after an invoice expired after which we are still monitoring for incoming payments. Defaults to the store's settings. (The default store settings is 1440, 1 day)",
|
||||||
"allOf": [ {"$ref": "#/components/schemas/TimeSpanMinutes"}]
|
"allOf": [ { "$ref": "#/components/schemas/TimeSpanMinutes" } ]
|
||||||
},
|
},
|
||||||
"paymentTolerance": {
|
"paymentTolerance": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
@@ -1109,7 +1137,7 @@
|
|||||||
},
|
},
|
||||||
"receivedDate": {
|
"receivedDate": {
|
||||||
"description": "The date the payment was recorded",
|
"description": "The date the payment was recorded",
|
||||||
"allOf": [ {"$ref": "#/components/schemas/UnixTimestamp"}]
|
"allOf": [ { "$ref": "#/components/schemas/UnixTimestamp" } ]
|
||||||
},
|
},
|
||||||
"value": {
|
"value": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
Reference in New Issue
Block a user