Fix SilverPay payment integration JSON serialization
- Changed JSON naming policy from CamelCase to SnakeCaseLower for SilverPay API compatibility - Fixed field name from 'fiat_amount' to 'amount' in request body - Used unique payment ID instead of order ID to avoid duplicate external_id conflicts - Modified SilverPayApiResponse to handle string amounts from API - Added [JsonIgnore] attributes to computed properties to prevent JSON serialization conflicts - Fixed test compilation errors (mock service and enum casting issues) - Updated SilverPay endpoint to http://10.0.0.52:8001/ 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
034b8facee
commit
5138242a99
@ -269,7 +269,7 @@ public class OrdersWithVariantsTests : IClassFixture<TestWebApplicationFactory>
|
|||||||
Price = 15.00m,
|
Price = 15.00m,
|
||||||
CategoryId = category.Id,
|
CategoryId = category.Id,
|
||||||
Weight = 1.0m,
|
Weight = 1.0m,
|
||||||
WeightUnit = (int)LittleShop.Enums.ProductWeightUnit.Kilograms
|
WeightUnit = LittleShop.Enums.ProductWeightUnit.Kilograms
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await _client.PostAsJsonAsync("/api/admin/products", productDto);
|
var response = await _client.PostAsJsonAsync("/api/admin/products", productDto);
|
||||||
|
|||||||
@ -19,13 +19,15 @@ namespace LittleShop.Tests.Unit;
|
|||||||
public class PushNotificationControllerTests
|
public class PushNotificationControllerTests
|
||||||
{
|
{
|
||||||
private readonly Mock<IPushNotificationService> _pushServiceMock;
|
private readonly Mock<IPushNotificationService> _pushServiceMock;
|
||||||
|
private readonly Mock<ITeleBotMessagingService> _teleBotServiceMock;
|
||||||
private readonly PushNotificationController _controller;
|
private readonly PushNotificationController _controller;
|
||||||
private readonly Guid _testUserId = Guid.NewGuid();
|
private readonly Guid _testUserId = Guid.NewGuid();
|
||||||
|
|
||||||
public PushNotificationControllerTests()
|
public PushNotificationControllerTests()
|
||||||
{
|
{
|
||||||
_pushServiceMock = new Mock<IPushNotificationService>();
|
_pushServiceMock = new Mock<IPushNotificationService>();
|
||||||
_controller = new PushNotificationController(_pushServiceMock.Object);
|
_teleBotServiceMock = new Mock<ITeleBotMessagingService>();
|
||||||
|
_controller = new PushNotificationController(_pushServiceMock.Object, _teleBotServiceMock.Object);
|
||||||
|
|
||||||
// Setup controller context for authenticated user
|
// Setup controller context for authenticated user
|
||||||
SetupControllerContext();
|
SetupControllerContext();
|
||||||
|
|||||||
@ -57,8 +57,11 @@ public class CryptoPaymentService : ICryptoPaymentService
|
|||||||
// Use SilverPAY
|
// Use SilverPAY
|
||||||
_logger.LogInformation("Creating SilverPAY order for {Currency}", currency);
|
_logger.LogInformation("Creating SilverPAY order for {Currency}", currency);
|
||||||
|
|
||||||
|
// Generate payment ID first to use as external_id
|
||||||
|
var paymentId = Guid.NewGuid();
|
||||||
|
|
||||||
var silverPayOrder = await _silverPayService.CreateOrderAsync(
|
var silverPayOrder = await _silverPayService.CreateOrderAsync(
|
||||||
order.Id.ToString(),
|
paymentId.ToString(), // Use unique payment ID instead of order ID
|
||||||
order.TotalAmount,
|
order.TotalAmount,
|
||||||
currency,
|
currency,
|
||||||
$"Order #{order.Id} - {order.Items.Count} items",
|
$"Order #{order.Id} - {order.Items.Count} items",
|
||||||
@ -67,7 +70,7 @@ public class CryptoPaymentService : ICryptoPaymentService
|
|||||||
|
|
||||||
var cryptoPayment = new CryptoPayment
|
var cryptoPayment = new CryptoPayment
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = paymentId, // Use the same payment ID
|
||||||
OrderId = orderId,
|
OrderId = orderId,
|
||||||
Currency = currency,
|
Currency = currency,
|
||||||
WalletAddress = silverPayOrder.PaymentAddress,
|
WalletAddress = silverPayOrder.PaymentAddress,
|
||||||
|
|||||||
@ -54,7 +54,7 @@ public class SilverPayService : ISilverPayService
|
|||||||
var request = new
|
var request = new
|
||||||
{
|
{
|
||||||
external_id = externalId,
|
external_id = externalId,
|
||||||
fiat_amount = amount, // Amount in GBP
|
amount = amount, // Amount in GBP
|
||||||
fiat_currency = "GBP",
|
fiat_currency = "GBP",
|
||||||
currency = currencyCode,
|
currency = currencyCode,
|
||||||
webhook_url = webhookUrl ?? _configuration["SilverPay:DefaultWebhookUrl"],
|
webhook_url = webhookUrl ?? _configuration["SilverPay:DefaultWebhookUrl"],
|
||||||
@ -63,14 +63,15 @@ public class SilverPayService : ISilverPayService
|
|||||||
|
|
||||||
var json = JsonSerializer.Serialize(request, new JsonSerializerOptions
|
var json = JsonSerializer.Serialize(request, new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
});
|
});
|
||||||
|
|
||||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
_logger.LogDebug("Creating SilverPAY order - External ID: {ExternalId}, Amount: {Amount} GBP, Currency: {Currency}",
|
_logger.LogInformation("Creating SilverPAY order - External ID: {ExternalId}, Amount: {Amount} GBP, Currency: {Currency}",
|
||||||
externalId, amount, currencyCode);
|
externalId, amount, currencyCode);
|
||||||
|
_logger.LogInformation("SilverPAY request body: {RequestBody}", json);
|
||||||
|
|
||||||
// Add timeout to prevent hanging
|
// Add timeout to prevent hanging
|
||||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
||||||
@ -260,7 +261,10 @@ public class SilverPayService : ISilverPayService
|
|||||||
public string ExternalId { get; set; } = string.Empty;
|
public string ExternalId { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("amount")]
|
[JsonPropertyName("amount")]
|
||||||
public decimal Amount { get; set; }
|
public string AmountString { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public decimal Amount => decimal.TryParse(AmountString, out var amount) ? amount : 0;
|
||||||
|
|
||||||
[JsonPropertyName("currency")]
|
[JsonPropertyName("currency")]
|
||||||
public string Currency { get; set; } = string.Empty;
|
public string Currency { get; set; } = string.Empty;
|
||||||
@ -284,7 +288,10 @@ public class SilverPayService : ISilverPayService
|
|||||||
public Dictionary<string, object>? PaymentDetails { get; set; }
|
public Dictionary<string, object>? PaymentDetails { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("crypto_amount")]
|
[JsonPropertyName("crypto_amount")]
|
||||||
public decimal? CryptoAmount { get; set; }
|
public string? CryptoAmountString { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public decimal? CryptoAmount => decimal.TryParse(CryptoAmountString, out var amount) ? amount : null;
|
||||||
|
|
||||||
[JsonPropertyName("tx_hash")]
|
[JsonPropertyName("tx_hash")]
|
||||||
public string? TransactionHash { get; set; }
|
public string? TransactionHash { get; set; }
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
"ExpiryInHours": 24
|
"ExpiryInHours": 24
|
||||||
},
|
},
|
||||||
"SilverPay": {
|
"SilverPay": {
|
||||||
"BaseUrl": "http://31.97.57.205:8001",
|
"BaseUrl": "http://10.0.0.52:8001",
|
||||||
"ApiKey": "sp_live_key_2025_production",
|
"ApiKey": "sp_live_key_2025_production",
|
||||||
"WebhookSecret": "webhook_secret_2025",
|
"WebhookSecret": "webhook_secret_2025",
|
||||||
"DefaultWebhookUrl": "http://localhost:8080/api/orders/payments/webhook",
|
"DefaultWebhookUrl": "http://localhost:8080/api/orders/payments/webhook",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user