diff --git a/BTCPayServer.Client/JsonConverters/DecimalStringJsonConverter.cs b/BTCPayServer.Client/JsonConverters/DecimalStringJsonConverter.cs deleted file mode 100644 index f3ec5c797..000000000 --- a/BTCPayServer.Client/JsonConverters/DecimalStringJsonConverter.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Globalization; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace BTCPayServer.JsonConverters -{ - public class DecimalStringJsonConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return (objectType == typeof(decimal) || objectType == typeof(decimal?)); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, - JsonSerializer serializer) - { - JToken token = JToken.Load(reader); - switch (token.Type) - { - case JTokenType.Float: - case JTokenType.Integer: - case JTokenType.String: - return decimal.Parse(token.ToString(), CultureInfo.InvariantCulture); - case JTokenType.Null when objectType == typeof(decimal?): - return null; - default: - throw new JsonSerializationException("Unexpected token type: " + - token.Type); - } - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value != null) - writer.WriteValue(((decimal)value).ToString(CultureInfo.InvariantCulture)); - } - } -} diff --git a/BTCPayServer.Client/JsonConverters/NumericStringJsonConverter.cs b/BTCPayServer.Client/JsonConverters/NumericStringJsonConverter.cs new file mode 100644 index 000000000..459bd1e0b --- /dev/null +++ b/BTCPayServer.Client/JsonConverters/NumericStringJsonConverter.cs @@ -0,0 +1,56 @@ +using System; +using System.Globalization; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace BTCPayServer.JsonConverters +{ + public class NumericStringJsonConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return (objectType == typeof(decimal) || + objectType == typeof(decimal?) || + objectType == typeof(double) || + objectType == typeof(double?)); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + JToken token = JToken.Load(reader); + switch (token.Type) + { + case JTokenType.Float: + case JTokenType.Integer: + case JTokenType.String: + if (objectType == typeof(decimal) || objectType == typeof(decimal?) ) + return decimal.Parse(token.ToString(), CultureInfo.InvariantCulture); + if (objectType == typeof(double) || objectType == typeof(double?)) + return double.Parse(token.ToString(), CultureInfo.InvariantCulture); + + throw new JsonSerializationException("Unexpected object type: " + objectType); + case JTokenType.Null when objectType == typeof(decimal?) || objectType == typeof(double?): + return null; + default: + throw new JsonSerializationException("Unexpected token type: " + + token.Type); + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + switch (value) + { + case null: + break; + case decimal x: + writer.WriteValue(x.ToString(CultureInfo.InvariantCulture)); + break; + case double x: + writer.WriteValue(x.ToString(CultureInfo.InvariantCulture)); + break; + } + } + } +} diff --git a/BTCPayServer.Client/Models/CreatePayoutRequest.cs b/BTCPayServer.Client/Models/CreatePayoutRequest.cs index d8b665b4b..cfc1e33b1 100644 --- a/BTCPayServer.Client/Models/CreatePayoutRequest.cs +++ b/BTCPayServer.Client/Models/CreatePayoutRequest.cs @@ -6,7 +6,7 @@ namespace BTCPayServer.Client.Models public class CreatePayoutRequest { public string Destination { get; set; } - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal? Amount { get; set; } public string PaymentMethod { get; set; } } diff --git a/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs b/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs index 474c35624..a314573ad 100644 --- a/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs +++ b/BTCPayServer.Client/Models/CreatePullPaymentRequest.cs @@ -8,7 +8,7 @@ namespace BTCPayServer.Client.Models public class CreatePullPaymentRequest { public string Name { get; set; } - [JsonProperty(ItemConverterType = typeof(DecimalStringJsonConverter))] + [JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))] public decimal Amount { get; set; } public string Currency { get; set; } [JsonConverter(typeof(TimeSpanJsonConverter))] diff --git a/BTCPayServer.Client/Models/PaymentRequestBaseData.cs b/BTCPayServer.Client/Models/PaymentRequestBaseData.cs index 4a61af99f..d573ef7f3 100644 --- a/BTCPayServer.Client/Models/PaymentRequestBaseData.cs +++ b/BTCPayServer.Client/Models/PaymentRequestBaseData.cs @@ -8,7 +8,7 @@ namespace BTCPayServer.Client.Models { public class PaymentRequestBaseData { - [JsonProperty(ItemConverterType = typeof(DecimalStringJsonConverter))] + [JsonProperty(ItemConverterType = typeof(NumericStringJsonConverter))] public decimal Amount { get; set; } public string Currency { get; set; } public DateTime? ExpiryDate { get; set; } diff --git a/BTCPayServer.Client/Models/PayoutData.cs b/BTCPayServer.Client/Models/PayoutData.cs index ea8698bf1..71a74fa72 100644 --- a/BTCPayServer.Client/Models/PayoutData.cs +++ b/BTCPayServer.Client/Models/PayoutData.cs @@ -21,9 +21,9 @@ namespace BTCPayServer.Client.Models public string PullPaymentId { get; set; } public string Destination { get; set; } public string PaymentMethod { get; set; } - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal Amount { get; set; } - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal? PaymentMethodAmount { get; set; } [JsonConverter(typeof(StringEnumConverter))] public PayoutState State { get; set; } diff --git a/BTCPayServer.Client/Models/PullPaymentBaseData.cs b/BTCPayServer.Client/Models/PullPaymentBaseData.cs index e9256621e..d95b60e06 100644 --- a/BTCPayServer.Client/Models/PullPaymentBaseData.cs +++ b/BTCPayServer.Client/Models/PullPaymentBaseData.cs @@ -14,7 +14,7 @@ namespace BTCPayServer.Client.Models public string Id { get; set; } public string Name { get; set; } public string Currency { get; set; } - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal Amount { get; set; } [JsonConverter(typeof(TimeSpanJsonConverter))] public TimeSpan? Period { get; set; } diff --git a/BTCPayServer.Tests/GreenfieldAPITests.cs b/BTCPayServer.Tests/GreenfieldAPITests.cs index 2bd699e87..1262e55e6 100644 --- a/BTCPayServer.Tests/GreenfieldAPITests.cs +++ b/BTCPayServer.Tests/GreenfieldAPITests.cs @@ -734,17 +734,18 @@ namespace BTCPayServer.Tests [Fact(Timeout = TestTimeout)] [Trait("Fast", "Fast")] - public void DecimalStringJsonConverterTests() + public void NumericJsonConverterTests() { JsonReader Get(string val) { return new JsonTextReader(new StringReader(val)); } - var jsonConverter = new DecimalStringJsonConverter(); + var jsonConverter = new NumericStringJsonConverter(); Assert.True(jsonConverter.CanConvert(typeof(decimal))); Assert.True(jsonConverter.CanConvert(typeof(decimal?))); - Assert.False(jsonConverter.CanConvert(typeof(double))); + Assert.True(jsonConverter.CanConvert(typeof(double))); + Assert.True(jsonConverter.CanConvert(typeof(double?))); Assert.False(jsonConverter.CanConvert(typeof(float))); Assert.False(jsonConverter.CanConvert(typeof(int))); Assert.False(jsonConverter.CanConvert(typeof(string))); @@ -755,12 +756,20 @@ namespace BTCPayServer.Tests Assert.Equal(1m, jsonConverter.ReadJson(Get(numberJson), typeof(decimal), null, null)); Assert.Equal(1.2m, jsonConverter.ReadJson(Get(numberDecimalJson), typeof(decimal), null, null)); Assert.Null(jsonConverter.ReadJson(Get("null"), typeof(decimal?), null, null)); + Assert.Equal((double)1.0, jsonConverter.ReadJson(Get(numberJson), typeof(double), null, null)); + Assert.Equal((double)1.2, jsonConverter.ReadJson(Get(numberDecimalJson), typeof(double), null, null)); + Assert.Null(jsonConverter.ReadJson(Get("null"), typeof(double?), null, null)); Assert.Throws(() => { jsonConverter.ReadJson(Get("null"), typeof(decimal), null, null); + });Assert.Throws(() => + { + jsonConverter.ReadJson(Get("null"), typeof(double), null, null); }); Assert.Equal(1.2m, jsonConverter.ReadJson(Get(stringJson), typeof(decimal), null, null)); Assert.Equal(1.2m, jsonConverter.ReadJson(Get(stringJson), typeof(decimal?), null, null)); + Assert.Equal(1.2, jsonConverter.ReadJson(Get(stringJson), typeof(double), null, null)); + Assert.Equal(1.2, jsonConverter.ReadJson(Get(stringJson), typeof(double?), null, null)); } } } diff --git a/BTCPayServer/Data/PullPaymentsExtensions.cs b/BTCPayServer/Data/PullPaymentsExtensions.cs index 3165f3de5..b29e872b8 100644 --- a/BTCPayServer/Data/PullPaymentsExtensions.cs +++ b/BTCPayServer/Data/PullPaymentsExtensions.cs @@ -149,9 +149,9 @@ namespace BTCPayServer.Data } public class PayoutBlob { - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal Amount { get; set; } - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal? CryptoAmount { get; set; } public int MinimumConfirmation { get; set; } = 1; public IClaimDestination Destination { get; set; } @@ -190,9 +190,9 @@ namespace BTCPayServer.Data public string Name { get; set; } public string Currency { get; set; } public int Divisibility { get; set; } - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal Limit { get; set; } - [JsonConverter(typeof(DecimalStringJsonConverter))] + [JsonConverter(typeof(NumericStringJsonConverter))] public decimal MinimumClaim { get; set; } public PullPaymentView View { get; set; } = new PullPaymentView(); [JsonConverter(typeof(TimeSpanJsonConverter))]