From 459f3c4a9368a39b0354e43b3502a854cd550ea4 Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Thu, 8 Apr 2021 09:42:18 +0200 Subject: [PATCH] Document and handle Invoice Metadata better (#2401) * Document and handle Invoice Metadata better PosData would crash in certain scenarios when created via API. Invoice metadata known fields were not completely documented * Fix value setter when null * fix swagger conformity * make all swagger invoice metadata optional looking in json --- .../Services/Invoices/InvoiceEntity.cs | 38 ++++- .../swagger/v1/swagger.template.invoices.json | 150 +++++++++++++++++- 2 files changed, 176 insertions(+), 12 deletions(-) diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs index 45e3c3797..1db57c503 100644 --- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs +++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs @@ -2,15 +2,12 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; -using Amazon.Runtime.Internal.Util; using BTCPayServer.Client.Models; using BTCPayServer.Data; using BTCPayServer.JsonConverters; using BTCPayServer.Models; using BTCPayServer.Payments; using BTCPayServer.Payments.Bitcoin; -using Microsoft.AspNetCore.Http.Extensions; -using Microsoft.CodeAnalysis; using NBitcoin; using NBitcoin.DataEncoders; using NBitpayClient; @@ -18,11 +15,10 @@ using NBXplorer; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; -using YamlDotNet.Core.Tokens; -using YamlDotNet.Serialization.NamingConventions; namespace BTCPayServer.Services.Invoices { + public class InvoiceMetadata { public static readonly JsonSerializer MetadataSerializer; @@ -64,7 +60,37 @@ namespace BTCPayServer.Services.Invoices [JsonProperty(PropertyName = "taxIncluded", DefaultValueHandling = DefaultValueHandling.Ignore)] public decimal? TaxIncluded { get; set; } - public string PosData { get; set; } + + [JsonIgnore] + public string PosData + { + get + { + return PosRawData?.ToString(); + } + set + { + if (value is null) + { + PosRawData = JValue.CreateNull(); + } + else + { + try + { + PosRawData = JToken.Parse(value); + } + catch (Exception ) + { + PosRawData = JToken.FromObject(value); + } + } + + } + } + + [JsonProperty(PropertyName = "posData")] + public JToken PosRawData { get; set; } [JsonExtensionData] public IDictionary AdditionalData { get; set; } diff --git a/BTCPayServer/wwwroot/swagger/v1/swagger.template.invoices.json b/BTCPayServer/wwwroot/swagger/v1/swagger.template.invoices.json index 0c0f16537..42bf1f9c5 100644 --- a/BTCPayServer/wwwroot/swagger/v1/swagger.template.invoices.json +++ b/BTCPayServer/wwwroot/swagger/v1/swagger.template.invoices.json @@ -734,6 +734,148 @@ } ] }, + "InvoiceMetadataPosString": { + "type": "string", + "description": "shown on the invoice details page" + }, + "InvoiceMetadataPosObject": { + "type": "object", + "description": "Any json object in any schema you want. Will be rendered on a best effort basis in terms of style on the invoice details UI" + }, + "InvoiceMetadata": { + "type": "object", + "additionalProperties": true, + "description": "Additional information around the invoice that can be supplied. The mentioned properties are all optional and you can introduce any json format you wish.", + "anyOf": [ + { + "properties": { + "orderId": { + "type": "string", + "nullable": true, + "description": "You can use this property to store the ID of an external system. We allow you to search in the invoice list based on this ID." + } + } + }, + { + "properties": { + "posData": { + "oneOf": [ + { + "$ref": "#/components/schemas/InvoiceMetadataPosString" + }, + { + "$ref": "#/components/schemas/InvoiceMetadataPosObject" + } + ] + } + } + }, + { + "properties": { + "buyerName": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerEmail": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerCountry": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerZip": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerState": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerCity": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerAddress1": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerAddress2": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "buyerPhone": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "itemDesc": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "itemCode": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "physical": { + "type": "string", + "nullable": true + } + } + }, + { + "properties": { + "taxIncluded": { + "type": "number", + "nullable": true + } + } + } + ] + }, "CreateInvoiceRequest": { "type": "object", "additionalProperties": false, @@ -749,9 +891,7 @@ "description": "The currency the invoice will use" }, "metadata": { - "type": "object", - "nullable": true, - "description": "Additional information around the invoice that can be supplied. Some metadata are treated differently by BTCPay Server: \n * `orderId`: A string, you can use this property to store the ID of an external system. We allow you to search in the invoice list based on this ID." + "$ref": "#/components/schemas/InvoiceMetadata" }, "checkout": { "nullable": true, @@ -769,9 +909,7 @@ "additionalProperties": false, "properties": { "metadata": { - "type": "object", - "nullable": true, - "description": "Additional information around the invoice that can be supplied." + "$ref": "#/components/schemas/InvoiceMetadata" } } },