using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using PnvPanel.Application.Auth; using PnvPanel.Application.Billing; using PnvPanel.Application.Common.Interfaces; using PnvPanel.Application.Common.Messaging; using PnvPanel.Application.Common.Models; using PnvPanel.Domain.Audit; using PnvPanel.Domain.Billing; namespace PnvPanel.Application.Admin.Billing; /// /// Продлевает оплату (max(текущий PaidUntil, сейчас) + период), возвращает в Active конфиги, /// приостановленные за неуплату (Expired), и синхронизирует ExpiresAt на все конфиги пользователя — /// зеркало UnblockUserCommandHandler, но по статусу Expired (биллинг), а не Disabled (блокировка). /// public sealed class ConfirmPaymentRequestCommandHandler( IAppDbContext dbContext, IIdentityService identityService, IXuiPanelGateway gateway, IRealtimeNotifier notifier, ITelegramNotifier telegramNotifier, ICurrentUser currentUser, ILogger logger ) : ICommandHandler { public async Task Handle( ConfirmPaymentRequestCommand command, CancellationToken cancellationToken ) { if (currentUser.UserId is not { } adminId) return Result.Failure(AuthErrors.Unauthorized); var request = await dbContext.PaymentRequests.FirstOrDefaultAsync( r => r.Id == command.RequestId, cancellationToken ); if (request is null) return Result.Failure(BillingErrors.RequestNotFound); if ( request.Status is not (PaymentRequestStatus.AwaitingPayment or PaymentRequestStatus.AwaitingConfirmation) ) return Result.Failure(BillingErrors.RequestNotDecidable); var profile = await identityService.GetProfileAsync(request.UserId, cancellationToken); if (profile is null) return Result.Failure(AuthErrors.Unauthorized); var now = DateTimeOffset.UtcNow; var baseline = profile.BillingPaidUntil is { } paidUntil && paidUntil > now ? paidUntil : now; var newPaidUntil = baseline.AddMonths(request.Period.ToMonths()); var extendResult = await identityService.ExtendBillingPaidUntilAsync( request.UserId, newPaidUntil, cancellationToken ); if (!extendResult.IsSuccess) return extendResult; request.Confirm(adminId); await BillingConfigResumer.ResumeConfigsAsync( dbContext, gateway, notifier, logger, request.UserId, newPaidUntil, cancellationToken ); dbContext.AuditLogs.Add( AuditLog.Create( adminId, "PaymentConfirmed", "PaymentRequest", request.Id.ToString(), metadata: null, AuditSource.Web ) ); await telegramNotifier.NotifyUserAsync( request.UserId, $"✅ Оплата подтверждена. Доступ продлён до {newPaidUntil:dd.MM.yyyy}.", null, cancellationToken ); return Result.Success(); } }