Refactor payment request handling to support role change top-ups
CI / Backend (build + test) (push) Successful in 1m19s
CI / Frontend (lint + typecheck + build) (push) Successful in 33s

- Updated the `PaymentRequest` model to include a new `Kind` property, distinguishing between `Subscription` and `RoleChangeTopUp` requests.
- Modified the `TelegramNotifier` to accommodate the new request type, ensuring accurate notifications for role change top-ups.
- Enhanced the `ConfirmPaymentRequestCommandHandler` to handle role change top-ups without extending the billing period, reflecting the new payment logic.
- Updated various application components and tests to support the new payment request structure and ensure proper functionality.
- Revised API documentation to clarify the behavior of role change top-ups and their impact on billing.
This commit is contained in:
Leonid Pershin
2026-07-19 16:45:17 +03:00
parent 0dcaf1203f
commit 5ff5224935
27 changed files with 1656 additions and 76 deletions
@@ -6,7 +6,8 @@ public sealed record AdminPaymentRequestDto(
Guid Id,
Guid UserId,
string UserName,
PaymentPeriod Period,
PaymentRequestKind Kind,
PaymentPeriod? Period,
int AmountSnapshot,
PaymentRequestStatus Status,
DateTimeOffset CreatedAt
@@ -50,9 +50,37 @@ public sealed class ConfirmPaymentRequestCommandHandler(
if (profile is null)
return Result.Failure(AuthErrors.Unauthorized);
// RoleChangeTopUp — доплата разницы в цене при апгрейде роли, не покупка времени: подтверждение
// не трогает BillingPaidUntil и не возвращает Expired-конфиги (это делает обычная Subscription-
// оплата/продление). Period не задан для этого Kind — ToMonths() здесь неприменим.
if (request.Kind == PaymentRequestKind.RoleChangeTopUp)
{
request.Confirm(adminId);
dbContext.AuditLogs.Add(
AuditLog.Create(
adminId,
"PaymentConfirmed",
"PaymentRequest",
request.Id.ToString(),
metadata: null,
AuditSource.Web
)
);
await telegramNotifier.NotifyUserAsync(
request.UserId,
"✅ Доплата за смену роли подтверждена.",
null,
cancellationToken
);
return Result.Success();
}
var now = DateTimeOffset.UtcNow;
var baseline = profile.BillingPaidUntil is { } paidUntil && paidUntil > now ? paidUntil : now;
var newPaidUntil = baseline.AddMonths(request.Period.ToMonths());
var newPaidUntil = baseline.AddMonths(request.Period!.Value.ToMonths());
var extendResult = await identityService.ExtendBillingPaidUntilAsync(
request.UserId,
@@ -36,6 +36,7 @@ public sealed class ListPaymentRequestsQueryHandler(
r.Id,
r.UserId,
userNames.GetValueOrDefault(r.UserId, "?"),
r.Kind,
r.Period,
r.AmountSnapshot,
r.Status,