using Microsoft.EntityFrameworkCore; using Tiku.Application.Commerce; using Tiku.Application.Tenancy; using Tiku.Domain.Tenancy; namespace Tiku.Infrastructure.Commerce; internal sealed partial class CommerceAdminService { public async Task> GetPaymentAccountsAsync( CommerceAdminActor actor, CommerceAdminQuery query, CancellationToken cancellationToken = default) { await AssertAdminAsync(actor, cancellationToken); var accounts = await providerConfigService.GetProvidersAsync( actor.TenantId, TenantExternalProviderCapability.Payment, string.IsNullOrWhiteSpace(query.Provider) ? null : NormalizeProvider(query.Provider), query.Limit, cancellationToken); return accounts.Select(ToPaymentAccountItem).ToArray(); } public async Task UpsertPaymentAccountAsync( CommerceAdminActor actor, UpsertPaymentAccountCommand command, CancellationToken cancellationToken = default) { await AssertAdminAsync(actor, cancellationToken); var account = await providerConfigService.UpsertProviderAsync( actor.TenantId, new UpsertTenantExternalProviderCommand( TenantExternalProviderCapability.Payment, command.Provider, command.Status, command.DisplayName, command.SecretRef, command.Priority, WithPaymentMode(command.ConfigPublic, command.Mode), JsonObjectOrDefault(default)), cancellationToken); return ToPaymentAccountItem(account); } public async Task UpsertTenantSecretAsync( CommerceAdminActor actor, UpsertTenantSecretCommand command, CancellationToken cancellationToken = default) { await AssertAdminAsync(actor, cancellationToken); var secretRef = string.IsNullOrWhiteSpace(command.SecretRef) ? $"tenant_secrets:{command.Purpose}:{NormalizeProvider(command.Provider)}:{command.SecretKey}" : command.SecretRef.Trim(); var provider = NormalizeProvider(command.Provider); var secret = await dbContext.TenantSecrets .SingleOrDefaultAsync(item => item.TenantId == actor.TenantId && item.SecretRef == secretRef, cancellationToken); if (secret is null) { secret = new TenantSecret { TenantId = actor.TenantId, SecretRef = secretRef }; dbContext.TenantSecrets.Add(secret); } else { secret.RotatedAt = DateTimeOffset.UtcNow; } var protectedPayload = tenantSecretProtector.Protect( actor.TenantId, secretRef, JsonObjectOrDefault(command.SecretPayload)); secret.Purpose = command.Purpose.Trim(); secret.Provider = provider; secret.SecretKey = command.SecretKey.Trim(); secret.Status = command.Status; secret.EncryptionKeyId = protectedPayload.KeyId; secret.EncryptedPayload = protectedPayload.Ciphertext; secret.EncryptionNonce = protectedPayload.Nonce; secret.EncryptionTag = protectedPayload.Tag; secret.ExpiresAt = command.ExpiresAt; await dbContext.SaveChangesAsync(cancellationToken); return ToSecretItem(secret); } }