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,
|
||||
DateTimeOffset? startDate = null,
|
||||
DateTimeOffset? endDate = null,
|
||||
string textSearch = null,
|
||||
bool includeArchived = false,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
@@ -28,7 +29,8 @@ namespace BTCPayServer.Client
|
||||
|
||||
if (orderId != null)
|
||||
queryPayload.Add(nameof(orderId), orderId);
|
||||
|
||||
if (textSearch != null)
|
||||
queryPayload.Add(nameof(textSearch), textSearch);
|
||||
if (status != null)
|
||||
queryPayload.Add(nameof(status), status.Select(s=> s.ToString().ToLower()).ToArray());
|
||||
|
||||
|
||||
@@ -7,35 +7,8 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Client.Models
|
||||
{
|
||||
public class CreateInvoiceRequest
|
||||
public class CreateInvoiceRequest : 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 string[] AdditionalSearchTerms { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,43 @@
|
||||
using System;
|
||||
using BTCPayServer.Client.JsonConverters;
|
||||
using BTCPayServer.JsonConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
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 StoreId { get; set; }
|
||||
|
||||
@@ -1035,10 +1035,17 @@ namespace BTCPayServer.Tests
|
||||
});
|
||||
await user.RegisterDerivationSchemeAsync("BTC");
|
||||
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
|
||||
}});
|
||||
},
|
||||
AdditionalSearchTerms = new string[] { "Banana" }
|
||||
});
|
||||
Assert.True(newInvoice.Checkout.RedirectAutomatically);
|
||||
Assert.Equal(user.StoreId, newInvoice.StoreId);
|
||||
//list
|
||||
@@ -1048,6 +1055,15 @@ namespace BTCPayServer.Tests
|
||||
Assert.Single(invoices);
|
||||
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
|
||||
var invoicesFiltered = await viewOnly.GetInvoices(user.StoreId,
|
||||
orderId: null, status: null, DateTimeOffset.Now.AddHours(-1),
|
||||
|
||||
@@ -54,7 +54,9 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
DateTimeOffset? startDate = null,
|
||||
[FromQuery]
|
||||
[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();
|
||||
if (store == null)
|
||||
@@ -79,7 +81,8 @@ namespace BTCPayServer.Controllers.GreenField
|
||||
StartDate = startDate,
|
||||
EndDate = endDate,
|
||||
OrderId = orderId,
|
||||
Status = status
|
||||
Status = status,
|
||||
TextSearch = textSearch
|
||||
});
|
||||
|
||||
return Ok(invoices.Select(ToModel));
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace BTCPayServer.Controllers
|
||||
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
|
||||
}
|
||||
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)
|
||||
@@ -183,10 +183,10 @@ namespace BTCPayServer.Controllers
|
||||
entity.RedirectURLTemplate = invoice.Checkout.RedirectURL?.Trim();
|
||||
if (additionalTags != null)
|
||||
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();
|
||||
logs.Write("Creation of invoice starting", InvoiceEventData.EventSeverity.Info);
|
||||
@@ -273,7 +273,7 @@ namespace BTCPayServer.Controllers
|
||||
|
||||
using (logs.Measure("Saving invoice"))
|
||||
{
|
||||
entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity);
|
||||
entity = await _InvoiceRepository.CreateInvoiceAsync(store.Id, entity, additionalSearchTerms);
|
||||
}
|
||||
_ = 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.Networks = _Networks;
|
||||
invoice.Id = Encoders.Base58.EncodeData(RandomUtils.GetBytes(16));
|
||||
@@ -210,6 +210,11 @@ namespace BTCPayServer.Services.Invoices
|
||||
textSearch.Add(invoice.Metadata.OrderId);
|
||||
textSearch.Add(invoice.StoreId);
|
||||
textSearch.Add(invoice.Metadata.BuyerEmail);
|
||||
|
||||
if (additionalSearchTerms != null)
|
||||
{
|
||||
textSearch.AddRange(additionalSearchTerms);
|
||||
}
|
||||
AddToTextSearch(context, invoiceData, textSearch.ToArray());
|
||||
|
||||
await context.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
@@ -35,6 +35,15 @@
|
||||
"description": "Array of statuses of invoices to be fetched",
|
||||
"$ref": "#/components/schemas/InvoiceStatus"
|
||||
},
|
||||
{
|
||||
"name": "textSearch",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"description": "A term that can help locating specific invoices.",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startDate",
|
||||
"in": "query",
|
||||
@@ -736,10 +745,36 @@
|
||||
"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": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/CreateInvoiceRequest"
|
||||
"$ref": "#/components/schemas/InvoiceDataBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
@@ -929,32 +964,25 @@
|
||||
]
|
||||
},
|
||||
"CreateInvoiceRequest": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/InvoiceDataBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"amount": {
|
||||
"type": "string",
|
||||
"format": "decimal",
|
||||
"description": "The amount of the invoice"
|
||||
"additionalSearchTerms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"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"
|
||||
"description": "Additional search term to help you find this invoice via text search",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"UpdateInvoiceRequest": {
|
||||
"type": "object",
|
||||
|
||||
Reference in New Issue
Block a user