130 lines
3.5 KiB
C#
130 lines
3.5 KiB
C#
using System.Text.Json;
|
|
|
|
namespace Tiku.Application.Commerce;
|
|
|
|
public static class PaymentProviders
|
|
{
|
|
public const string WechatPay = "wechat_pay";
|
|
public const string Alipay = "alipay";
|
|
public const string Manual = "manual";
|
|
}
|
|
|
|
public sealed record PaymentProviderAccount(
|
|
Guid TenantId,
|
|
string Provider,
|
|
string Mode,
|
|
JsonElement ConfigPublic,
|
|
JsonElement SecretPayload);
|
|
|
|
public sealed record CreatePaymentProviderRequest(
|
|
Guid TenantId,
|
|
string OrderNo,
|
|
string Subject,
|
|
int AmountCents,
|
|
string Method,
|
|
string? OpenId,
|
|
string? ReturnUrl,
|
|
string? QuitUrl,
|
|
string NotifyUrl,
|
|
JsonElement Metadata);
|
|
|
|
public sealed record CreatePaymentProviderResult(
|
|
string Provider,
|
|
string Method,
|
|
string Status,
|
|
string? ProviderTradeNo,
|
|
JsonElement ClientPayload,
|
|
JsonElement RawPayload);
|
|
|
|
public sealed record PaymentNotificationRequest(
|
|
Guid TenantId,
|
|
string Provider,
|
|
IReadOnlyDictionary<string, string> Headers,
|
|
string RawBody,
|
|
JsonElement Body);
|
|
|
|
public sealed record PaymentNotificationResult(
|
|
string Provider,
|
|
string EventType,
|
|
string EventId,
|
|
string OrderNo,
|
|
string? ProviderTradeNo,
|
|
int AmountCents,
|
|
bool Paid,
|
|
bool SignatureValid,
|
|
DateTimeOffset? PaidAt,
|
|
JsonElement RawPayload);
|
|
|
|
public sealed record CreateRefundProviderRequest(
|
|
Guid TenantId,
|
|
string OrderNo,
|
|
string RefundNo,
|
|
string? ProviderTradeNo,
|
|
int AmountCents,
|
|
string Reason,
|
|
JsonElement Metadata);
|
|
|
|
public sealed record CreateRefundProviderResult(
|
|
string Provider,
|
|
bool Succeeded,
|
|
string? ProviderRefundNo,
|
|
JsonElement RawPayload);
|
|
|
|
public interface IPaymentProvider
|
|
{
|
|
string Provider { get; }
|
|
|
|
Task<CreatePaymentProviderResult> CreatePaymentAsync(
|
|
PaymentProviderAccount account,
|
|
CreatePaymentProviderRequest request,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
Task<PaymentNotificationResult> ParsePaymentNotificationAsync(
|
|
PaymentProviderAccount account,
|
|
PaymentNotificationRequest request,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
Task<CreateRefundProviderResult> CreateRefundAsync(
|
|
PaymentProviderAccount account,
|
|
CreateRefundProviderRequest request,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
return Task.FromException<CreateRefundProviderResult>(new PaymentProviderException(
|
|
"Payment provider refund is not configured.",
|
|
"payment_provider_refund_not_supported"));
|
|
}
|
|
}
|
|
|
|
public interface IPaymentProviderGateway
|
|
{
|
|
Task<CreatePaymentProviderResult> CreatePaymentAsync(
|
|
string provider,
|
|
CreatePaymentProviderRequest request,
|
|
CancellationToken cancellationToken = default);
|
|
|
|
Task<PaymentNotificationResult> ParsePaymentNotificationAsync(
|
|
string provider,
|
|
PaymentNotificationRequest request,
|
|
CancellationToken cancellationToken = default);
|
|
}
|
|
|
|
public interface IPaymentProviderConfigService
|
|
{
|
|
Task<PaymentProviderAccount> GetActiveAccountAsync(
|
|
Guid tenantId,
|
|
string provider,
|
|
CancellationToken cancellationToken = default);
|
|
}
|
|
|
|
public interface ITenantSecretService
|
|
{
|
|
Task<JsonElement> GetActiveSecretPayloadAsync(
|
|
Guid tenantId,
|
|
string secretRef,
|
|
CancellationToken cancellationToken = default);
|
|
}
|
|
|
|
public sealed class PaymentProviderException(string message, string code) : Exception(message)
|
|
{
|
|
public string Code { get; } = code;
|
|
} |