payment methods
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
// src/Webshop.Api/JsonConverters/AdminPaymentMethodDtoConverter.cs
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Webshop.Application.DTOs.Payments;
|
||||
using Webshop.Domain.Enums;
|
||||
|
||||
namespace Webshop.Api.JsonConverters
|
||||
{
|
||||
public class AdminPaymentMethodDtoConverter : JsonConverter<AdminPaymentMethodDto>
|
||||
{
|
||||
public override AdminPaymentMethodDto Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
throw new JsonException("Expected StartObject token.");
|
||||
}
|
||||
|
||||
// Ein temporäres JsonDocument erstellen, um das Objekt zu analysieren
|
||||
using var jsonDocument = JsonDocument.ParseValue(ref reader);
|
||||
var jsonObject = jsonDocument.RootElement;
|
||||
|
||||
var dto = new AdminPaymentMethodDto();
|
||||
|
||||
// Lese alle Standard-Eigenschaften
|
||||
if (jsonObject.TryGetProperty(nameof(AdminPaymentMethodDto.Id), out var idElement))
|
||||
{
|
||||
dto.Id = idElement.GetGuid();
|
||||
}
|
||||
|
||||
if (jsonObject.TryGetProperty(nameof(AdminPaymentMethodDto.Name), out var nameElement))
|
||||
{
|
||||
dto.Name = nameElement.GetString() ?? string.Empty;
|
||||
}
|
||||
|
||||
if (jsonObject.TryGetProperty(nameof(AdminPaymentMethodDto.Description), out var descriptionElement))
|
||||
{
|
||||
dto.Description = descriptionElement.GetString();
|
||||
}
|
||||
|
||||
if (jsonObject.TryGetProperty(nameof(AdminPaymentMethodDto.IsActive), out var isActiveElement))
|
||||
{
|
||||
dto.IsActive = isActiveElement.GetBoolean();
|
||||
}
|
||||
|
||||
if (jsonObject.TryGetProperty(nameof(AdminPaymentMethodDto.ProcessingFee), out var processingFeeElement))
|
||||
{
|
||||
dto.ProcessingFee = processingFeeElement.GetDecimal();
|
||||
}
|
||||
|
||||
// Lese den PaymentGatewayType, um zu entscheiden, wie die Konfiguration deserialisiert werden soll
|
||||
if (!jsonObject.TryGetProperty(nameof(AdminPaymentMethodDto.PaymentGatewayType), out var typeElement) ||
|
||||
!Enum.TryParse<PaymentGatewayType>(typeElement.GetString(), true, out var gatewayType))
|
||||
{
|
||||
throw new JsonException("PaymentGatewayType is missing or invalid.");
|
||||
}
|
||||
dto.PaymentGatewayType = gatewayType;
|
||||
|
||||
// Deserialisiere die Konfiguration basierend auf dem Typ
|
||||
if (jsonObject.TryGetProperty(nameof(AdminPaymentMethodDto.Configuration), out var configElement) && configElement.ValueKind != JsonValueKind.Null)
|
||||
{
|
||||
var configOptions = new JsonSerializerOptions(options); // Klonen der Optionen
|
||||
configOptions.Converters.Remove(this); // Entferne diesen Konverter, um eine Endlosschleife zu vermeiden
|
||||
|
||||
switch (gatewayType)
|
||||
{
|
||||
case PaymentGatewayType.BankTransfer:
|
||||
dto.Configuration = configElement.Deserialize<BankTransferConfigurationDto>(configOptions);
|
||||
break;
|
||||
case PaymentGatewayType.Stripe:
|
||||
dto.Configuration = configElement.Deserialize<StripeConfigurationDto>(configOptions);
|
||||
break;
|
||||
case PaymentGatewayType.PayPal:
|
||||
dto.Configuration = configElement.Deserialize<PayPalConfigurationDto>(configOptions);
|
||||
break;
|
||||
// Fügen Sie hier weitere Fälle hinzu
|
||||
default:
|
||||
// Behandeln Sie den Fall, dass keine spezifische Konfiguration benötigt wird
|
||||
dto.Configuration = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, AdminPaymentMethodDto value, JsonSerializerOptions options)
|
||||
{
|
||||
var writeOptions = new JsonSerializerOptions(options);
|
||||
writeOptions.Converters.Remove(this); // Entferne diesen Konverter, um eine Endlosschleife zu vermeiden
|
||||
|
||||
writer.WriteStartObject();
|
||||
|
||||
writer.WriteString("id", value.Id);
|
||||
writer.WriteString("name", value.Name);
|
||||
writer.WriteString("description", value.Description);
|
||||
writer.WriteBoolean("isActive", value.IsActive);
|
||||
// Schreibe den Enum als String
|
||||
writer.WriteString("paymentGatewayType", value.PaymentGatewayType.ToString());
|
||||
|
||||
if (value.Configuration != null)
|
||||
{
|
||||
writer.WritePropertyName("configuration");
|
||||
// Serialisiere das Konfigurationsobjekt mit seinem konkreten Typ
|
||||
JsonSerializer.Serialize(writer, value.Configuration, value.Configuration.GetType(), writeOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteNull("configuration");
|
||||
}
|
||||
|
||||
if (value.ProcessingFee.HasValue)
|
||||
{
|
||||
writer.WriteNumber("processingFee", value.ProcessingFee.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteNull("processingFee");
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// src/Webshop.Application/DTOs/Payments/AdminPaymentMethodDto.cs
|
||||
using System;
|
||||
using Webshop.Domain.Enums;
|
||||
using System.Text.Json.Serialization; // Für JsonConverter
|
||||
|
||||
namespace Webshop.Application.DTOs.Payments
|
||||
{
|
||||
@@ -11,7 +11,11 @@ namespace Webshop.Application.DTOs.Payments
|
||||
public string? Description { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public PaymentGatewayType PaymentGatewayType { get; set; }
|
||||
public string? Configuration { get; set; } // Als JSON-String, den der Admin bearbeitet
|
||||
|
||||
// Configuration ist jetzt ein Objekt, das je nach PaymentGatewayType
|
||||
// eine Instanz von BankTransferConfigurationDto, StripeConfigurationDto etc. sein wird.
|
||||
public object? Configuration { get; set; }
|
||||
|
||||
public decimal? ProcessingFee { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// src/Webshop.Application/DTOs/Payments/BankTransferConfigurationDto.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Webshop.Application.DTOs.Payments;
|
||||
|
||||
public class BankTransferConfigurationDto : IPaymentMethodConfiguration
|
||||
{
|
||||
[Required]
|
||||
public string IBAN { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public string BIC { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public string BankName { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// src/Webshop.Application/DTOs/Payments/IPaymentMethodConfiguration.cs
|
||||
namespace Webshop.Application.DTOs.Payments;
|
||||
|
||||
// Leeres Marker-Interface für polymorphe Deserialisierung
|
||||
public interface IPaymentMethodConfiguration { }
|
||||
18
Webshop.Application/DTOs/Payments/PayPalConfigurationDto.cs
Normal file
18
Webshop.Application/DTOs/Payments/PayPalConfigurationDto.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Webshop.Application.DTOs.Payments
|
||||
{
|
||||
public class PayPalConfigurationDto : IPaymentMethodConfiguration
|
||||
{
|
||||
[Required]
|
||||
public string ClientId { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public string ClientSecret { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
19
Webshop.Application/DTOs/Payments/StripeConfigurationDto.cs
Normal file
19
Webshop.Application/DTOs/Payments/StripeConfigurationDto.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Webshop.Application.DTOs.Payments
|
||||
{
|
||||
public class StripeConfigurationDto : IPaymentMethodConfiguration
|
||||
{
|
||||
[Required]
|
||||
public string PublicKey { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public string SecretKey { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
// src/Webshop.Application/Services/Admin/AdminPaymentMethodService.cs
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq; // Für Select
|
||||
using System.Linq;
|
||||
using System.Text.Json; // Wichtig für JsonSerializer
|
||||
using System.Threading.Tasks;
|
||||
using Webshop.Application.DTOs.Payments; // AdminPaymentMethodDto
|
||||
using Webshop.Application.DTOs.Payments; // AdminPaymentMethodDto und die neuen Configuration-DTOs
|
||||
using Webshop.Domain.Entities; // PaymentMethod
|
||||
using Webshop.Domain.Enums; // PaymentGatewayType
|
||||
using Webshop.Domain.Interfaces; // IPaymentMethodRepository
|
||||
using Webshop.Domain.Enums;
|
||||
|
||||
namespace Webshop.Application.Services.Admin
|
||||
{
|
||||
@@ -30,7 +31,8 @@ namespace Webshop.Application.Services.Admin
|
||||
Description = pm.Description,
|
||||
IsActive = pm.IsActive,
|
||||
PaymentGatewayType = pm.PaymentGatewayType,
|
||||
Configuration = pm.Configuration, // Gibt den JSON-String für den Admin zurück
|
||||
// Deserialisiere den JSON-String aus der DB in ein Objekt für die Admin-Ansicht
|
||||
Configuration = pm.Configuration != null ? JsonSerializer.Deserialize<object>(pm.Configuration) : null,
|
||||
ProcessingFee = pm.ProcessingFee
|
||||
}).ToList();
|
||||
}
|
||||
@@ -47,27 +49,36 @@ namespace Webshop.Application.Services.Admin
|
||||
Description = paymentMethod.Description,
|
||||
IsActive = paymentMethod.IsActive,
|
||||
PaymentGatewayType = paymentMethod.PaymentGatewayType,
|
||||
Configuration = paymentMethod.Configuration,
|
||||
// Deserialisiere den JSON-String aus der DB in ein Objekt
|
||||
Configuration = paymentMethod.Configuration != null ? JsonSerializer.Deserialize<object>(paymentMethod.Configuration) : null,
|
||||
ProcessingFee = paymentMethod.ProcessingFee
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<AdminPaymentMethodDto> CreateAsync(AdminPaymentMethodDto paymentMethodDto)
|
||||
{
|
||||
var (isValid, configJson, errorMessage) = ValidateAndSerializeConfiguration(paymentMethodDto.PaymentGatewayType, paymentMethodDto.Configuration);
|
||||
if (!isValid)
|
||||
{
|
||||
// In einer echten Anwendung würden Sie hier eine benutzerdefinierte Validierungs-Exception werfen,
|
||||
// damit der Controller einen 400 Bad Request zurückgeben kann.
|
||||
throw new ArgumentException(errorMessage);
|
||||
}
|
||||
|
||||
var newPaymentMethod = new PaymentMethod
|
||||
{
|
||||
Id = Guid.NewGuid(), // API generiert die ID
|
||||
Id = Guid.NewGuid(),
|
||||
Name = paymentMethodDto.Name,
|
||||
Description = paymentMethodDto.Description,
|
||||
IsActive = paymentMethodDto.IsActive,
|
||||
PaymentGatewayType = paymentMethodDto.PaymentGatewayType,
|
||||
Configuration = paymentMethodDto.Configuration,
|
||||
Configuration = configJson, // Speichere den validierten JSON-String
|
||||
ProcessingFee = paymentMethodDto.ProcessingFee
|
||||
};
|
||||
|
||||
await _paymentMethodRepository.AddAsync(newPaymentMethod);
|
||||
|
||||
paymentMethodDto.Id = newPaymentMethod.Id; // ID zurückschreiben
|
||||
paymentMethodDto.Id = newPaymentMethod.Id;
|
||||
return paymentMethodDto;
|
||||
}
|
||||
|
||||
@@ -76,12 +87,17 @@ namespace Webshop.Application.Services.Admin
|
||||
var existingPaymentMethod = await _paymentMethodRepository.GetByIdAsync(paymentMethodDto.Id);
|
||||
if (existingPaymentMethod == null) return false;
|
||||
|
||||
// Eigenschaften aktualisieren
|
||||
var (isValid, configJson, errorMessage) = ValidateAndSerializeConfiguration(paymentMethodDto.PaymentGatewayType, paymentMethodDto.Configuration);
|
||||
if (!isValid)
|
||||
{
|
||||
throw new ArgumentException(errorMessage);
|
||||
}
|
||||
|
||||
existingPaymentMethod.Name = paymentMethodDto.Name;
|
||||
existingPaymentMethod.Description = paymentMethodDto.Description;
|
||||
existingPaymentMethod.IsActive = paymentMethodDto.IsActive;
|
||||
existingPaymentMethod.PaymentGatewayType = paymentMethodDto.PaymentGatewayType;
|
||||
existingPaymentMethod.Configuration = paymentMethodDto.Configuration;
|
||||
existingPaymentMethod.Configuration = configJson;
|
||||
existingPaymentMethod.ProcessingFee = paymentMethodDto.ProcessingFee;
|
||||
|
||||
await _paymentMethodRepository.UpdateAsync(existingPaymentMethod);
|
||||
@@ -96,5 +112,51 @@ namespace Webshop.Application.Services.Admin
|
||||
await _paymentMethodRepository.DeleteAsync(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
private (bool IsValid, string? ConfigJson, string? ErrorMessage) ValidateAndSerializeConfiguration(PaymentGatewayType type, object? configObject)
|
||||
{
|
||||
if (configObject == null) return (true, null, null);
|
||||
|
||||
var configElement = (JsonElement)configObject;
|
||||
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PaymentGatewayType.BankTransfer:
|
||||
var bankConfig = configElement.Deserialize<BankTransferConfigurationDto>();
|
||||
if (bankConfig == null || string.IsNullOrEmpty(bankConfig.IBAN) || string.IsNullOrEmpty(bankConfig.BIC))
|
||||
{
|
||||
return (false, null, "Für Banküberweisung müssen IBAN und BIC angegeben werden.");
|
||||
}
|
||||
return (true, JsonSerializer.Serialize(bankConfig), null);
|
||||
|
||||
case PaymentGatewayType.Stripe:
|
||||
var stripeConfig = configElement.Deserialize<StripeConfigurationDto>();
|
||||
if (stripeConfig == null || string.IsNullOrEmpty(stripeConfig.PublicKey) || string.IsNullOrEmpty(stripeConfig.SecretKey))
|
||||
{
|
||||
return (false, null, "Für Stripe müssen PublicKey und SecretKey angegeben werden.");
|
||||
}
|
||||
return (true, JsonSerializer.Serialize(stripeConfig), null);
|
||||
|
||||
case PaymentGatewayType.PayPal:
|
||||
var payPalConfig = configElement.Deserialize<PayPalConfigurationDto>();
|
||||
if (payPalConfig == null || string.IsNullOrEmpty(payPalConfig.ClientId) || string.IsNullOrEmpty(payPalConfig.ClientSecret))
|
||||
{
|
||||
return (false, null, "Für PayPal müssen ClientId und ClientSecret angegeben werden.");
|
||||
}
|
||||
return (true, JsonSerializer.Serialize(payPalConfig), null);
|
||||
|
||||
default:
|
||||
// Für Typen wie Invoice oder CashOnDelivery, die keine spezielle Konfiguration brauchen,
|
||||
// ist ein leeres JSON-Objekt '{}' ein gültiger Wert.
|
||||
return (true, JsonSerializer.Serialize(new object()), null);
|
||||
}
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
return (false, null, $"Ungültiges JSON-Format für die Konfiguration: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user