feat: Implement Club Membership features including activation and retrieval of membership status
- Added command and handler for activating club membership with optional activation code and duration. - Created response DTO for club membership activation. - Implemented query and handler to retrieve current user's club membership status. - Added necessary Protobuf service calls for club membership operations. - Introduced new queries for retrieving network statistics and network tree structure. - Enhanced commission queries to fetch user commission payouts and weekly balances. - Updated application contract context to include new services for club and network memberships.
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
/// <summary>
|
||||
/// دریافت لیست پرداختهای کمیسیون کاربر جاری
|
||||
/// </summary>
|
||||
public record GetMyCommissionPayoutsQuery : IRequest<GetMyCommissionPayoutsResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شماره هفته در فرمت ISO (مثال: "2025-W48"، null = همه)
|
||||
/// </summary>
|
||||
public string? WeekNumber { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// وضعیت: 0=Pending, 1=Calculated, 2=Paid, 3=Withdrawn (null = همه)
|
||||
/// </summary>
|
||||
public int? Status { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره صفحه (1-based, internally converted to 0-based PageIndex)
|
||||
/// </summary>
|
||||
public int PageNumber { get; init; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// تعداد در صفحه
|
||||
/// </summary>
|
||||
public int PageSize { get; init; } = 20;
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Commission;
|
||||
|
||||
namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
public class GetMyCommissionPayoutsQueryHandler : IRequestHandler<GetMyCommissionPayoutsQuery, GetMyCommissionPayoutsResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public GetMyCommissionPayoutsQueryHandler(
|
||||
IApplicationContractContext context,
|
||||
ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<GetMyCommissionPayoutsResponseDto> Handle(GetMyCommissionPayoutsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
// Fixed: Use PageIndex (0-based) not PageNumber (1-based), and WeekNumber is string
|
||||
var cmsRequest = new GetUserCommissionPayoutsRequest
|
||||
{
|
||||
UserId = userId, // long? type in proto - just assign directly
|
||||
PageIndex = Math.Max(0, request.PageNumber - 1), // Convert 1-based to 0-based
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
|
||||
// WeekNumber is string type in proto - assign directly
|
||||
if (!string.IsNullOrEmpty(request.WeekNumber))
|
||||
cmsRequest.WeekNumber = request.WeekNumber;
|
||||
|
||||
if (request.Status.HasValue)
|
||||
cmsRequest.Status = request.Status.Value; // int? type in proto
|
||||
|
||||
var response = await _context.Commission.GetUserCommissionPayoutsAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||
|
||||
var payouts = response.Models.Select(p => new CommissionPayoutDto
|
||||
{
|
||||
Id = p.Id,
|
||||
WeekNumber = p.WeekNumber,
|
||||
WeekLabel = $"هفته {p.WeekNumber}",
|
||||
BalancesEarned = p.BalancesEarned,
|
||||
TotalAmount = p.TotalAmount,
|
||||
AmountFormatted = FormatCurrency(p.TotalAmount),
|
||||
Status = MapStatus(p.Status),
|
||||
StatusBadgeColor = GetStatusColor(p.Status),
|
||||
CalculatedDate = p.Created?.ToDateTime() ?? DateTime.UtcNow,
|
||||
DatePersian = FormatPersianDate(p.Created?.ToDateTime())
|
||||
}).ToList();
|
||||
|
||||
return new GetMyCommissionPayoutsResponseDto
|
||||
{
|
||||
Payouts = payouts,
|
||||
TotalCount = (int)response.MetaData.TotalCount,
|
||||
PageNumber = request.PageNumber,
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
}
|
||||
|
||||
private static string MapStatus(int status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
0 => "Pending",
|
||||
1 => "Calculated",
|
||||
2 => "Paid",
|
||||
3 => "Withdrawn",
|
||||
_ => "Unknown"
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetStatusColor(int status)
|
||||
{
|
||||
return status switch
|
||||
{
|
||||
0 => "warning",
|
||||
1 => "info",
|
||||
2 => "success",
|
||||
3 => "success",
|
||||
_ => "default"
|
||||
};
|
||||
}
|
||||
|
||||
private static string FormatCurrency(long amount)
|
||||
{
|
||||
return $"{amount:N0} تومان";
|
||||
}
|
||||
|
||||
private static string FormatPersianDate(DateTime? date)
|
||||
{
|
||||
if (!date.HasValue) return string.Empty;
|
||||
// TODO: استفاده از PersianCalendar
|
||||
return date.Value.ToString("yyyy/MM/dd");
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
|
||||
|
||||
public class GetMyCommissionPayoutsResponseDto
|
||||
{
|
||||
public List<CommissionPayoutDto> Payouts { get; set; } = new();
|
||||
public int TotalCount { get; set; }
|
||||
public int PageNumber { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
}
|
||||
|
||||
public class CommissionPayoutDto
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره هفته (e.g., "2024-W45")
|
||||
/// </summary>
|
||||
public string WeekNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// لیبل هفته (هفته 45 - آذر 1403)
|
||||
/// </summary>
|
||||
public string WeekLabel { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// تعداد Balance کسب شده
|
||||
/// </summary>
|
||||
public int BalancesEarned { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ کل
|
||||
/// </summary>
|
||||
public long TotalAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مبلغ فرمت شده
|
||||
/// </summary>
|
||||
public string AmountFormatted { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// وضعیت (Pending/Calculated/Paid/Withdrawn)
|
||||
/// </summary>
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// رنگ Badge
|
||||
/// </summary>
|
||||
public string StatusBadgeColor { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ محاسبه
|
||||
/// </summary>
|
||||
public DateTime CalculatedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ شمسی
|
||||
/// </summary>
|
||||
public string DatePersian { get; set; } = string.Empty;
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
|
||||
|
||||
/// <summary>
|
||||
/// دریافت تعادل هفتگی کاربر جاری
|
||||
/// </summary>
|
||||
public record GetMyWeeklyBalancesQuery : IRequest<GetMyWeeklyBalancesResponseDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// شماره هفته در فرمت ISO (مثال: "2025-W48"، null = هفته جاری)
|
||||
/// </summary>
|
||||
public string? WeekNumber { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// فقط تعادلهای فعال (غیر منقضی)
|
||||
/// </summary>
|
||||
public bool OnlyActive { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// شماره صفحه (1-based)
|
||||
/// </summary>
|
||||
public int PageNumber { get; init; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// تعداد در صفحه
|
||||
/// </summary>
|
||||
public int PageSize { get; init; } = 10;
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
using CMSMicroservice.Protobuf.Protos.Commission;
|
||||
|
||||
namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
|
||||
|
||||
public class GetMyWeeklyBalancesQueryHandler : IRequestHandler<GetMyWeeklyBalancesQuery, GetMyWeeklyBalancesResponseDto>
|
||||
{
|
||||
private readonly IApplicationContractContext _context;
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public GetMyWeeklyBalancesQueryHandler(
|
||||
IApplicationContractContext context,
|
||||
ICurrentUserService currentUserService)
|
||||
{
|
||||
_context = context;
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public async Task<GetMyWeeklyBalancesResponseDto> Handle(GetMyWeeklyBalancesQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||
|
||||
// Fixed: Use proto-aligned request
|
||||
var cmsRequest = new GetUserWeeklyBalancesRequest
|
||||
{
|
||||
UserId = userId,
|
||||
OnlyActive = request.OnlyActive,
|
||||
PageIndex = Math.Max(0, request.PageNumber - 1), // Convert 1-based to 0-based
|
||||
PageSize = request.PageSize
|
||||
};
|
||||
|
||||
// WeekNumber is string in proto (format: "YYYY-Www")
|
||||
if (!string.IsNullOrEmpty(request.WeekNumber))
|
||||
cmsRequest.WeekNumber = request.WeekNumber;
|
||||
|
||||
var response = await _context.Commission.GetUserWeeklyBalancesAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||
|
||||
// Map list of UserWeeklyBalanceModel to DTO
|
||||
var balances = response.Models.Select(b => new WeeklyBalanceItemDto
|
||||
{
|
||||
Id = b.Id,
|
||||
WeekNumber = b.WeekNumber,
|
||||
LeftLegBalances = b.LeftLegBalances,
|
||||
RightLegBalances = b.RightLegBalances,
|
||||
TotalBalances = b.TotalBalances,
|
||||
WeeklyPoolContribution = b.WeeklyPoolContribution,
|
||||
CalculatedAt = b.CalculatedAt?.ToDateTime(),
|
||||
IsExpired = b.IsExpired
|
||||
}).ToList();
|
||||
|
||||
// Calculate summary
|
||||
var totalLeft = balances.Sum(b => b.LeftLegBalances);
|
||||
var totalRight = balances.Sum(b => b.RightLegBalances);
|
||||
var weakerLeg = totalLeft < totalRight ? "Left" : "Right";
|
||||
|
||||
return new GetMyWeeklyBalancesResponseDto
|
||||
{
|
||||
Balances = balances,
|
||||
TotalCount = (int)response.MetaData.TotalCount,
|
||||
PageNumber = request.PageNumber,
|
||||
PageSize = request.PageSize,
|
||||
TotalLeftBalances = totalLeft,
|
||||
TotalRightBalances = totalRight,
|
||||
WeakerLeg = weakerLeg
|
||||
};
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
|
||||
|
||||
public class GetMyWeeklyBalancesResponseDto
|
||||
{
|
||||
/// <summary>
|
||||
/// لیست تعادلهای هفتگی
|
||||
/// </summary>
|
||||
public List<WeeklyBalanceItemDto> Balances { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// تعداد کل رکوردها
|
||||
/// </summary>
|
||||
public int TotalCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره صفحه
|
||||
/// </summary>
|
||||
public int PageNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعداد در صفحه
|
||||
/// </summary>
|
||||
public int PageSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مجموع تعادل پای چپ
|
||||
/// </summary>
|
||||
public int TotalLeftBalances { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مجموع تعادل پای راست
|
||||
/// </summary>
|
||||
public int TotalRightBalances { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// پای ضعیفتر (Left/Right)
|
||||
/// </summary>
|
||||
public string WeakerLeg { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class WeeklyBalanceItemDto
|
||||
{
|
||||
/// <summary>
|
||||
/// شناسه رکورد
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// شماره هفته (فرمت: "2025-W48")
|
||||
/// </summary>
|
||||
public string WeekNumber { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// تعادل پای چپ
|
||||
/// </summary>
|
||||
public int LeftLegBalances { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تعادل پای راست
|
||||
/// </summary>
|
||||
public int RightLegBalances { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// مجموع تعادل
|
||||
/// </summary>
|
||||
public int TotalBalances { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// سهم از استخر هفتگی
|
||||
/// </summary>
|
||||
public long WeeklyPoolContribution { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// تاریخ محاسبه
|
||||
/// </summary>
|
||||
public DateTime? CalculatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// آیا منقضی شده؟
|
||||
/// </summary>
|
||||
public bool IsExpired { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user