Files
tiku-backend.net/Tiku.Infrastructure/PlatformBilling/PlatformBillingPaymentGateway.cs

92 lines
4.2 KiB
C#

using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Tiku.Application.Commerce;
using Tiku.Application.PlatformBilling;
using Tiku.Application.Security;
using Tiku.Domain.Tenancy;
using Tiku.Infrastructure.Persistence;
namespace Tiku.Infrastructure.PlatformBilling;
internal sealed class PlatformBillingPaymentGateway(
ITenantExecutionScope tenantExecutionScope) : IPlatformBillingPaymentGateway
{
public Task<CreatePaymentProviderResult> CreatePaymentAsync(
string provider,
CreatePaymentProviderRequest request,
CancellationToken cancellationToken = default) =>
ExecuteAsync(provider, request.OrderNo, async (resolvedProvider, account, token) =>
await resolvedProvider.CreatePaymentAsync(account, request, token), cancellationToken);
public Task<PaymentNotificationResult> ParseNotificationAsync(
string provider,
PaymentNotificationRequest request,
CancellationToken cancellationToken = default) =>
ExecuteAsync(provider, "payment-notification", async (resolvedProvider, account, token) =>
await resolvedProvider.ParsePaymentNotificationAsync(account, request, token), cancellationToken);
private Task<TResult> ExecuteAsync<TResult>(
string provider,
string correlationId,
Func<IPaymentProvider, PaymentProviderAccount, CancellationToken, Task<TResult>> operation,
CancellationToken cancellationToken)
{
return tenantExecutionScope.ExecuteAsync(
new SystemScopeRequest(
null,
SystemScopeCallerType.Platform,
nameof(PlatformBillingPaymentGateway),
"Resolve the platform-owned SaaS billing payment account",
correlationId,
IsGlobal: true),
async (services, token) =>
{
var dbContext = services.GetRequiredService<TikuDbContext>();
var platformTenantId = await dbContext.Tenants.AsNoTracking()
.Where(value => value.Mode == TenantMode.PlatformOwned)
.Select(value => value.Id)
.SingleOrDefaultAsync(token);
if (platformTenantId == Guid.Empty)
{
throw new PaymentProviderException("Platform-owned tenant is missing.", "platform_payment_owner_missing");
}
var normalized = NormalizeProvider(provider);
var resolvedProvider = services.GetServices<IPaymentProvider>()
.SingleOrDefault(value => value.Provider == normalized)
?? throw new PaymentProviderException("Payment provider is not supported.", "payment_provider_not_supported");
PaymentProviderAccount account;
if (normalized == PaymentProviders.Manual)
{
account = new PaymentProviderAccount(
platformTenantId,
PaymentProviders.Manual,
"PlatformCollect",
JsonDocument.Parse("{}").RootElement.Clone(),
JsonDocument.Parse("{}").RootElement.Clone());
}
else
{
account = await services.GetRequiredService<IPaymentProviderConfigService>()
.GetActiveAccountAsync(platformTenantId, normalized, token);
}
return await operation(resolvedProvider, account, token);
},
cancellationToken);
}
private static string NormalizeProvider(string provider)
{
var normalized = provider.Trim().ToLowerInvariant().Replace("-", "_", StringComparison.Ordinal);
return normalized switch
{
"wechat" or "wechatpay" or "wxpay" or "wx_pay" => PaymentProviders.WechatPay,
"ali_pay" => PaymentProviders.Alipay,
PaymentProviders.WechatPay or PaymentProviders.Alipay or PaymentProviders.Manual => normalized,
_ => throw new PaymentProviderException("Payment provider is not supported.", "payment_provider_not_supported")
};
}
}