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:
@@ -0,0 +1,22 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// فعالسازی عضویت باشگاه کاربر جاری (پرداخت 56M)
|
||||||
|
/// </summary>
|
||||||
|
public record ActivateMyClubMembershipCommand : IRequest<ActivateMyClubMembershipResponseDto>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// شناسه پکیج (PackageId)
|
||||||
|
/// </summary>
|
||||||
|
public long PackageId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// کد فعالسازی (اختیاری)
|
||||||
|
/// </summary>
|
||||||
|
public string? ActivationCode { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// مدت زمان عضویت به ماه (پیشفرض: 12)
|
||||||
|
/// </summary>
|
||||||
|
public int DurationMonths { get; init; } = 12;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using CMSMicroservice.Protobuf.Protos.ClubMembership;
|
||||||
|
|
||||||
|
namespace FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
|
||||||
|
|
||||||
|
public class ActivateMyClubMembershipCommandHandler : IRequestHandler<ActivateMyClubMembershipCommand, ActivateMyClubMembershipResponseDto>
|
||||||
|
{
|
||||||
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
|
||||||
|
public ActivateMyClubMembershipCommandHandler(
|
||||||
|
IApplicationContractContext context,
|
||||||
|
ICurrentUserService currentUserService)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ActivateMyClubMembershipResponseDto> Handle(ActivateMyClubMembershipCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||||
|
|
||||||
|
var grpcRequest = new ActivateClubMembershipRequest
|
||||||
|
{
|
||||||
|
UserId = userId,
|
||||||
|
PackageId = request.PackageId,
|
||||||
|
DurationMonths = request.DurationMonths
|
||||||
|
};
|
||||||
|
|
||||||
|
// اگر کد فعالسازی ارسال شده، اضافه کن
|
||||||
|
if (!string.IsNullOrEmpty(request.ActivationCode))
|
||||||
|
{
|
||||||
|
grpcRequest.ActivationCode = request.ActivationCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.ClubMemberships.ActivateClubMembershipAsync(
|
||||||
|
grpcRequest,
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
var activationDate = DateTime.UtcNow;
|
||||||
|
var expirationDate = activationDate.AddMonths(request.DurationMonths);
|
||||||
|
|
||||||
|
return new ActivateMyClubMembershipResponseDto
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Message = "عضویت باشگاه با موفقیت فعال شد",
|
||||||
|
ActivationDate = activationDate,
|
||||||
|
ExpirationDate = expirationDate,
|
||||||
|
AmountPaid = 56_000_000 // 56M تومان
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
|
||||||
|
|
||||||
|
public class ActivateMyClubMembershipResponseDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// آیا فعالسازی موفق بود؟
|
||||||
|
/// </summary>
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// پیام نتیجه
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تاریخ فعالسازی
|
||||||
|
/// </summary>
|
||||||
|
public DateTime ActivationDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تاریخ انقضا
|
||||||
|
/// </summary>
|
||||||
|
public DateTime ExpirationDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// مبلغ پرداخت شده
|
||||||
|
/// </summary>
|
||||||
|
public long AmountPaid { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت وضعیت عضویت باشگاه کاربر جاری
|
||||||
|
/// </summary>
|
||||||
|
public record GetMyClubMembershipQuery : IRequest<GetMyClubMembershipResponseDto>;
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using CMSMicroservice.Protobuf.Protos.ClubMembership;
|
||||||
|
|
||||||
|
namespace FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
|
||||||
|
|
||||||
|
public class GetMyClubMembershipQueryHandler : IRequestHandler<GetMyClubMembershipQuery, GetMyClubMembershipResponseDto>
|
||||||
|
{
|
||||||
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
|
||||||
|
public GetMyClubMembershipQueryHandler(
|
||||||
|
IApplicationContractContext context,
|
||||||
|
ICurrentUserService currentUserService)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GetMyClubMembershipResponseDto> Handle(GetMyClubMembershipQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||||
|
|
||||||
|
var cmsRequest = new GetClubMembershipRequest
|
||||||
|
{
|
||||||
|
UserId = userId
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _context.ClubMemberships.GetClubMembershipAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
// Fixed: Use ActivatedAt and ExpiresAt from proto (not ActivationDate/ExpirationDate)
|
||||||
|
var activationDate = response.ActivatedAt?.ToDateTime();
|
||||||
|
var expirationDate = response.ExpiresAt?.ToDateTime();
|
||||||
|
|
||||||
|
var daysRemaining = expirationDate.HasValue
|
||||||
|
? Math.Max(0, (int)(expirationDate.Value - DateTime.UtcNow).TotalDays)
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
return new GetMyClubMembershipResponseDto
|
||||||
|
{
|
||||||
|
UserId = response.UserId,
|
||||||
|
IsActive = response.IsActive,
|
||||||
|
ActivationDate = activationDate,
|
||||||
|
ExpirationDate = expirationDate,
|
||||||
|
PackageId = response.PackageId,
|
||||||
|
PackageName = response.PackageName,
|
||||||
|
ActivationCode = response.ActivationCode,
|
||||||
|
Status = DetermineStatus(response.IsActive, expirationDate),
|
||||||
|
DaysRemaining = daysRemaining,
|
||||||
|
IsTrialPeriod = !response.IsActive && daysRemaining > 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string DetermineStatus(bool isActive, DateTime? expirationDate)
|
||||||
|
{
|
||||||
|
if (!isActive && !expirationDate.HasValue)
|
||||||
|
return "Inactive";
|
||||||
|
|
||||||
|
if (!isActive && expirationDate.HasValue && expirationDate.Value < DateTime.UtcNow)
|
||||||
|
return "Expired";
|
||||||
|
|
||||||
|
if (!isActive)
|
||||||
|
return "Trial";
|
||||||
|
|
||||||
|
return "Active";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
|
||||||
|
|
||||||
|
public class GetMyClubMembershipResponseDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// شناسه کاربر
|
||||||
|
/// </summary>
|
||||||
|
public long UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// شناسه پکیج
|
||||||
|
/// </summary>
|
||||||
|
public long PackageId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نام پکیج
|
||||||
|
/// </summary>
|
||||||
|
public string PackageName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// کد فعالسازی
|
||||||
|
/// </summary>
|
||||||
|
public string ActivationCode { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// وضعیت فعال/غیرفعال
|
||||||
|
/// </summary>
|
||||||
|
public bool IsActive { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تاریخ فعالسازی (mapped from ActivatedAt)
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ActivationDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تاریخ انقضا (mapped from ExpiresAt)
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ExpirationDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نوع عضویت (Trial/Active/Expired/Inactive)
|
||||||
|
/// </summary>
|
||||||
|
public string Status { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تعداد روزهای باقیمانده
|
||||||
|
/// </summary>
|
||||||
|
public int DaysRemaining { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// آیا در دوره آزمایشی است؟
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTrialPeriod { get; set; }
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
|
}
|
||||||
@@ -5,4 +5,12 @@ public class ForbiddenAccessException : Exception
|
|||||||
public ForbiddenAccessException() : base()
|
public ForbiddenAccessException() : base()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ForbiddenAccessException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForbiddenAccessException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using CMSMicroservice.Protobuf.Protos.Category;
|
using CMSMicroservice.Protobuf.Protos.Category;
|
||||||
using CMSMicroservice.Protobuf.Protos.OtpToken;
|
using CMSMicroservice.Protobuf.Protos.OtpToken;
|
||||||
using CMSMicroservice.Protobuf.Protos.Package;
|
using CMSMicroservice.Protobuf.Protos.Package;
|
||||||
using CMSMicroservice.Protobuf.Protos.PruductCategory;
|
using CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||||
using CMSMicroservice.Protobuf.Protos.Products;
|
using CMSMicroservice.Protobuf.Protos.Products;
|
||||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||||
using CMSMicroservice.Protobuf.Protos.User;
|
using CMSMicroservice.Protobuf.Protos.User;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
||||||
@@ -14,6 +14,8 @@ using CMSMicroservice.Protobuf.Protos.UserContract;
|
|||||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
||||||
|
using CMSMicroservice.Protobuf.Protos.ClubMembership;
|
||||||
|
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||||
using PYMSMicroservice.Protobuf.Protos.Transaction;
|
using PYMSMicroservice.Protobuf.Protos.Transaction;
|
||||||
|
|
||||||
namespace FrontOffice.BFF.Application.Common.Interfaces;
|
namespace FrontOffice.BFF.Application.Common.Interfaces;
|
||||||
@@ -29,10 +31,10 @@ public interface IApplicationContractContext
|
|||||||
#region CMS
|
#region CMS
|
||||||
PackageContract.PackageContractClient Package { get; }
|
PackageContract.PackageContractClient Package { get; }
|
||||||
ProductsContract.ProductsContractClient Product { get; }
|
ProductsContract.ProductsContractClient Product { get; }
|
||||||
ProductGallerysContract.ProductGallerysContractClient ProductGallerys { get; }
|
ProductGalleriesContract.ProductGalleriesContractClient ProductGalleries { get; }
|
||||||
ProductImagesContract.ProductImagesContractClient ProductImages { get; }
|
ProductImagesContract.ProductImagesContractClient ProductImages { get; }
|
||||||
CategoryContract.CategoryContractClient Category { get; }
|
CategoryContract.CategoryContractClient Category { get; }
|
||||||
PruductCategoryContract.PruductCategoryContractClient ProductCategory { get; }
|
ProductCategoryContract.ProductCategoryContractClient ProductCategory { get; }
|
||||||
UserCartsContract.UserCartsContractClient UserCart { get; }
|
UserCartsContract.UserCartsContractClient UserCart { get; }
|
||||||
UserContract.UserContractClient User { get; }
|
UserContract.UserContractClient User { get; }
|
||||||
UserContractContract.UserContractContractClient UserContract { get; }
|
UserContractContract.UserContractContractClient UserContract { get; }
|
||||||
@@ -43,6 +45,10 @@ public interface IApplicationContractContext
|
|||||||
UserWalletChangeLogContract.UserWalletChangeLogContractClient UserWalletChangeLog { get; }
|
UserWalletChangeLogContract.UserWalletChangeLogContractClient UserWalletChangeLog { get; }
|
||||||
ConfigurationContract.ConfigurationContractClient Configuration { get; }
|
ConfigurationContract.ConfigurationContractClient Configuration { get; }
|
||||||
CommissionContract.CommissionContractClient Commission { get; }
|
CommissionContract.CommissionContractClient Commission { get; }
|
||||||
|
|
||||||
|
// Network & Club System
|
||||||
|
ClubMembershipContract.ClubMembershipContractClient ClubMemberships { get; }
|
||||||
|
NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships { get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PYMS
|
#region PYMS
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
<ProjectReference Include="..\FrontOffice.BFF.Domain\FrontOffice.BFF.Domain.csproj" />
|
<ProjectReference Include="..\FrontOffice.BFF.Domain\FrontOffice.BFF.Domain.csproj" />
|
||||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.UserOrder.Protobuf\FrontOffice.BFF.UserOrder.Protobuf.csproj" />
|
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.UserOrder.Protobuf\FrontOffice.BFF.UserOrder.Protobuf.csproj" />
|
||||||
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.Category.Protobuf\FrontOffice.BFF.Category.Protobuf.csproj" />
|
<ProjectReference Include="..\Protobufs\FrontOffice.BFF.Category.Protobuf\FrontOffice.BFF.Category.Protobuf.csproj" />
|
||||||
|
<!-- CMS Protobuf for Commission, ClubMembership, NetworkMembership, Configuration -->
|
||||||
|
<ProjectReference Include="..\..\..\CMS\src\CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت آمار شبکه کاربر جاری
|
||||||
|
/// </summary>
|
||||||
|
public record GetMyNetworkStatisticsQuery : IRequest<GetMyNetworkStatisticsResponseDto>;
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||||
|
|
||||||
|
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
|
||||||
|
|
||||||
|
public class GetMyNetworkStatisticsQueryHandler : IRequestHandler<GetMyNetworkStatisticsQuery, GetMyNetworkStatisticsResponseDto>
|
||||||
|
{
|
||||||
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
|
||||||
|
public GetMyNetworkStatisticsQueryHandler(
|
||||||
|
IApplicationContractContext context,
|
||||||
|
ICurrentUserService currentUserService)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GetMyNetworkStatisticsResponseDto> Handle(GetMyNetworkStatisticsQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||||
|
|
||||||
|
// Note: GetNetworkStatisticsRequest is empty (returns overall stats)
|
||||||
|
// For user-specific stats, we need to use GetUserNetwork instead
|
||||||
|
var cmsRequest = new GetNetworkStatisticsRequest();
|
||||||
|
|
||||||
|
var response = await _context.NetworkMemberships.GetNetworkStatisticsAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
// Also get user's own network info for personal stats
|
||||||
|
var userNetworkRequest = new GetUserNetworkRequest { UserId = userId };
|
||||||
|
var userNetwork = await _context.NetworkMemberships.GetUserNetworkAsync(userNetworkRequest, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
var weakerLeg = response.LeftLegCount < response.RightLegCount ? "Left" : "Right";
|
||||||
|
|
||||||
|
// Find last member from TopUsers if available
|
||||||
|
var lastMember = response.TopUsers.LastOrDefault();
|
||||||
|
|
||||||
|
return new GetMyNetworkStatisticsResponseDto
|
||||||
|
{
|
||||||
|
// Overall network stats
|
||||||
|
TotalMembers = response.TotalMembers,
|
||||||
|
ActiveMembers = response.ActiveMembers,
|
||||||
|
LeftLegCount = response.LeftLegCount,
|
||||||
|
RightLegCount = response.RightLegCount,
|
||||||
|
LeftPercentage = response.LeftPercentage,
|
||||||
|
RightPercentage = response.RightPercentage,
|
||||||
|
AverageDepth = response.AverageDepth,
|
||||||
|
MaxDepth = response.MaxDepth,
|
||||||
|
WeakerLeg = weakerLeg,
|
||||||
|
|
||||||
|
// User's personal info
|
||||||
|
MyNetworkLevel = userNetwork.NetworkLevel,
|
||||||
|
MyNetworkLeg = userNetwork.NetworkLeg == 0 ? "Left" : "Right",
|
||||||
|
MyReferralCode = userNetwork.ReferralCode,
|
||||||
|
|
||||||
|
// Last member info
|
||||||
|
LastMember = lastMember != null ? new LastMemberDto
|
||||||
|
{
|
||||||
|
UserId = lastMember.UserId,
|
||||||
|
FullName = lastMember.UserName,
|
||||||
|
Position = lastMember.LeftCount > lastMember.RightCount ? "Left" : "Right",
|
||||||
|
TotalChildren = lastMember.TotalChildren
|
||||||
|
} : null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
|
||||||
|
|
||||||
|
public class GetMyNetworkStatisticsResponseDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// تعداد کل اعضا
|
||||||
|
/// </summary>
|
||||||
|
public int TotalMembers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تعداد اعضای فعال
|
||||||
|
/// </summary>
|
||||||
|
public int ActiveMembers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تعداد اعضای پای چپ
|
||||||
|
/// </summary>
|
||||||
|
public int LeftLegCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تعداد اعضای پای راست
|
||||||
|
/// </summary>
|
||||||
|
public int RightLegCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// درصد پای چپ
|
||||||
|
/// </summary>
|
||||||
|
public double LeftPercentage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// درصد پای راست
|
||||||
|
/// </summary>
|
||||||
|
public double RightPercentage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// میانگین عمق درخت
|
||||||
|
/// </summary>
|
||||||
|
public double AverageDepth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// حداکثر عمق درخت
|
||||||
|
/// </summary>
|
||||||
|
public int MaxDepth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// پای ضعیفتر (Weaker Leg)
|
||||||
|
/// </summary>
|
||||||
|
public string WeakerLeg { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سطح کاربر در شبکه
|
||||||
|
/// </summary>
|
||||||
|
public int MyNetworkLevel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// پای کاربر در شبکه (Left/Right)
|
||||||
|
/// </summary>
|
||||||
|
public string MyNetworkLeg { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// کد معرفی کاربر
|
||||||
|
/// </summary>
|
||||||
|
public string MyReferralCode { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// آخرین عضو اضافه شده
|
||||||
|
/// </summary>
|
||||||
|
public LastMemberDto? LastMember { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LastMemberDto
|
||||||
|
{
|
||||||
|
public long UserId { get; set; }
|
||||||
|
public string FullName { get; set; } = string.Empty;
|
||||||
|
public string Position { get; set; } = string.Empty;
|
||||||
|
public int TotalChildren { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت درخت شبکه باینری کاربر جاری
|
||||||
|
/// </summary>
|
||||||
|
public record GetMyNetworkTreeQuery : IRequest<GetMyNetworkTreeResponseDto>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// حداکثر عمق درخت (1-10)
|
||||||
|
/// </summary>
|
||||||
|
public int MaxDepth { get; init; } = 3;
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||||
|
|
||||||
|
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
|
||||||
|
|
||||||
|
public class GetMyNetworkTreeQueryHandler : IRequestHandler<GetMyNetworkTreeQuery, GetMyNetworkTreeResponseDto>
|
||||||
|
{
|
||||||
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
|
||||||
|
public GetMyNetworkTreeQueryHandler(
|
||||||
|
IApplicationContractContext context,
|
||||||
|
ICurrentUserService currentUserService)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GetMyNetworkTreeResponseDto> Handle(GetMyNetworkTreeQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||||
|
|
||||||
|
var cmsRequest = new GetNetworkTreeRequest
|
||||||
|
{
|
||||||
|
RootUserId = userId,
|
||||||
|
MaxDepth = Math.Clamp(request.MaxDepth, 1, 10) // محدود کردن بین 1-10
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await _context.NetworkMemberships.GetNetworkTreeAsync(cmsRequest, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
// CMS returns flat list (repeated NetworkTreeNodeModel nodes)
|
||||||
|
// We need to build tree structure from it
|
||||||
|
var rootNode = BuildTreeFromFlatList(response.Nodes.ToList(), userId);
|
||||||
|
|
||||||
|
return new GetMyNetworkTreeResponseDto
|
||||||
|
{
|
||||||
|
RootNode = rootNode,
|
||||||
|
TotalMembers = response.Nodes.Count,
|
||||||
|
CurrentDepth = CalculateDepth(rootNode)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build hierarchical tree from flat list returned by CMS
|
||||||
|
/// </summary>
|
||||||
|
private NetworkNodeDto? BuildTreeFromFlatList(List<NetworkTreeNodeModel> flatNodes, long rootUserId)
|
||||||
|
{
|
||||||
|
if (flatNodes == null || flatNodes.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Create lookup dictionary for O(1) access
|
||||||
|
var nodeDict = flatNodes.ToDictionary(n => n.UserId);
|
||||||
|
|
||||||
|
// Find root node
|
||||||
|
var rootCmsNode = flatNodes.FirstOrDefault(n => n.UserId == rootUserId);
|
||||||
|
if (rootCmsNode == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Build tree recursively
|
||||||
|
return BuildNodeRecursive(rootCmsNode, flatNodes, nodeDict, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetworkNodeDto BuildNodeRecursive(
|
||||||
|
NetworkTreeNodeModel cmsNode,
|
||||||
|
List<NetworkTreeNodeModel> allNodes,
|
||||||
|
Dictionary<long, NetworkTreeNodeModel> nodeDict,
|
||||||
|
int level)
|
||||||
|
{
|
||||||
|
// Find children (nodes that have this node as parent)
|
||||||
|
var leftChild = allNodes.FirstOrDefault(n =>
|
||||||
|
n.ParentId.HasValue && n.ParentId.Value == cmsNode.UserId && n.NetworkLeg == 0); // 0 = Left
|
||||||
|
var rightChild = allNodes.FirstOrDefault(n =>
|
||||||
|
n.ParentId.HasValue && n.ParentId.Value == cmsNode.UserId && n.NetworkLeg == 1); // 1 = Right
|
||||||
|
|
||||||
|
var position = level == 0 ? "Root" : (cmsNode.NetworkLeg == 0 ? "Left" : "Right");
|
||||||
|
|
||||||
|
return new NetworkNodeDto
|
||||||
|
{
|
||||||
|
UserId = cmsNode.UserId,
|
||||||
|
FullName = cmsNode.UserName ?? string.Empty,
|
||||||
|
Mobile = string.Empty, // Proto doesn't have mobile, add if needed
|
||||||
|
Avatar = null, // Proto doesn't have avatar
|
||||||
|
Position = position,
|
||||||
|
Level = level,
|
||||||
|
LeftChild = leftChild != null ? BuildNodeRecursive(leftChild, allNodes, nodeDict, level + 1) : null,
|
||||||
|
RightChild = rightChild != null ? BuildNodeRecursive(rightChild, allNodes, nodeDict, level + 1) : null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CalculateDepth(NetworkNodeDto? node)
|
||||||
|
{
|
||||||
|
if (node == null) return 0;
|
||||||
|
return 1 + Math.Max(CalculateDepth(node.LeftChild), CalculateDepth(node.RightChild));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
|
||||||
|
|
||||||
|
public class GetMyNetworkTreeResponseDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// نود ریشه (کاربر جاری)
|
||||||
|
/// </summary>
|
||||||
|
public NetworkNodeDto? RootNode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// تعداد کل اعضا در درخت
|
||||||
|
/// </summary>
|
||||||
|
public int TotalMembers { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// عمق فعلی درخت
|
||||||
|
/// </summary>
|
||||||
|
public int CurrentDepth { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NetworkNodeDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// شناسه کاربر
|
||||||
|
/// </summary>
|
||||||
|
public long UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// نام کاربر
|
||||||
|
/// </summary>
|
||||||
|
public string FullName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// موبایل
|
||||||
|
/// </summary>
|
||||||
|
public string Mobile { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// آواتار
|
||||||
|
/// </summary>
|
||||||
|
public string? Avatar { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// موقعیت در درخت (Root/Left/Right)
|
||||||
|
/// </summary>
|
||||||
|
public string Position { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// فرزند چپ
|
||||||
|
/// </summary>
|
||||||
|
public NetworkNodeDto? LeftChild { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// فرزند راست
|
||||||
|
/// </summary>
|
||||||
|
public NetworkNodeDto? RightChild { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سطح در درخت (0 = root)
|
||||||
|
/// </summary>
|
||||||
|
public int Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// آیا فرزند دارد؟
|
||||||
|
/// </summary>
|
||||||
|
public bool HasChildren => LeftChild != null || RightChild != null;
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CMSCategory = CMSMicroservice.Protobuf.Protos.Category;
|
using CMSCategory = CMSMicroservice.Protobuf.Protos.Category;
|
||||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||||
using CMSMicroservice.Protobuf.Protos.Products;
|
using CMSMicroservice.Protobuf.Protos.Products;
|
||||||
using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
|
using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||||
|
|
||||||
namespace FrontOffice.BFF.Application.ProductsCQ.Queries.GetProducts;
|
namespace FrontOffice.BFF.Application.ProductsCQ.Queries.GetProducts;
|
||||||
public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProductsResponseDto>
|
public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProductsResponseDto>
|
||||||
@@ -28,10 +28,10 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProd
|
|||||||
|
|
||||||
var dto = response.Adapt<GetProductsResponseDto>();
|
var dto = response.Adapt<GetProductsResponseDto>();
|
||||||
|
|
||||||
var galleryResponse = await _context.ProductGallerys.GetAllProductGallerysByFilterAsync(
|
var galleryResponse = await _context.ProductGalleries.GetAllProductGalleriesByFilterAsync(
|
||||||
new GetAllProductGallerysByFilterRequest
|
new GetAllProductGalleriesByFilterRequest
|
||||||
{
|
{
|
||||||
Filter = new GetAllProductGallerysByFilterFilter()
|
Filter = new GetAllProductGalleriesByFilterFilter()
|
||||||
}, cancellationToken: cancellationToken);
|
}, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
var relatedItems = galleryResponse?.Models?.Where(x => x.ProductId == request.Id).ToList();
|
var relatedItems = galleryResponse?.Models?.Where(x => x.ProductId == request.Id).ToList();
|
||||||
@@ -82,10 +82,10 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProd
|
|||||||
var categoryLookup = categoriesResponse.Models?
|
var categoryLookup = categoriesResponse.Models?
|
||||||
.ToDictionary(c => c.Id) ?? new Dictionary<long, CMSCategory.GetAllCategoryByFilterResponseModel>();
|
.ToDictionary(c => c.Id) ?? new Dictionary<long, CMSCategory.GetAllCategoryByFilterResponseModel>();
|
||||||
|
|
||||||
var productCategoryResponse = await _context.ProductCategory.GetAllPruductCategoryByFilterAsync(
|
var productCategoryResponse = await _context.ProductCategory.GetAllProductCategoryByFilterAsync(
|
||||||
new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
|
new CMSProductCategory.GetAllProductCategoryByFilterRequest
|
||||||
{
|
{
|
||||||
Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
|
Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
|
||||||
{
|
{
|
||||||
ProductId = productId
|
ProductId = productId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,16 +1,32 @@
|
|||||||
|
using CMSMicroservice.Protobuf.Protos.User;
|
||||||
|
|
||||||
namespace FrontOffice.BFF.Application.UserCQ.Commands.DeleteUser;
|
namespace FrontOffice.BFF.Application.UserCQ.Commands.DeleteUser;
|
||||||
public class DeleteUserCommandHandler : IRequestHandler<DeleteUserCommand, Unit>
|
public class DeleteUserCommandHandler : IRequestHandler<DeleteUserCommand, Unit>
|
||||||
{
|
{
|
||||||
private readonly IApplicationContractContext _context;
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
|
||||||
public DeleteUserCommandHandler(IApplicationContractContext context)
|
public DeleteUserCommandHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Unit> Handle(DeleteUserCommand request, CancellationToken cancellationToken)
|
public async Task<Unit> Handle(DeleteUserCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
//TODO: Implement your business logic
|
// Security check: User can only delete their own account
|
||||||
return new Unit();
|
var currentUserId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated");
|
||||||
|
|
||||||
|
if (request.Id != currentUserId)
|
||||||
|
{
|
||||||
|
throw new ForbiddenAccessException("You can only delete your own account");
|
||||||
|
}
|
||||||
|
|
||||||
|
await _context.User.DeleteUserAsync(new DeleteUserRequest
|
||||||
|
{
|
||||||
|
Id = request.Id
|
||||||
|
}, cancellationToken: cancellationToken);
|
||||||
|
|
||||||
|
return Unit.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,29 @@
|
|||||||
namespace FrontOffice.BFF.Application.UserWalletCQ.Commands.TransferUserWalletBallance;
|
namespace FrontOffice.BFF.Application.UserWalletCQ.Commands.TransferUserWalletBallance;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// انتقال موجودی کیف پول - نیاز به پیادهسازی در CMS
|
||||||
|
/// TODO: این قابلیت نیاز به افزودن rpc TransferBalance در userwallet.proto دارد
|
||||||
|
/// </summary>
|
||||||
public class TransferUserWalletBallanceCommandHandler : IRequestHandler<TransferUserWalletBallanceCommand, Unit>
|
public class TransferUserWalletBallanceCommandHandler : IRequestHandler<TransferUserWalletBallanceCommand, Unit>
|
||||||
{
|
{
|
||||||
private readonly IApplicationContractContext _context;
|
private readonly IApplicationContractContext _context;
|
||||||
|
private readonly ICurrentUserService _currentUserService;
|
||||||
|
|
||||||
public TransferUserWalletBallanceCommandHandler(IApplicationContractContext context)
|
public TransferUserWalletBallanceCommandHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
_currentUserService = currentUserService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Unit> Handle(TransferUserWalletBallanceCommand request, CancellationToken cancellationToken)
|
public async Task<Unit> Handle(TransferUserWalletBallanceCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
//TODO: Implement your business logic
|
// TODO: این قابلیت نیاز به پیادهسازی در CMS دارد
|
||||||
return new Unit();
|
// 1. افزودن rpc TransferBalance در userwallet.proto
|
||||||
|
// 2. پیادهسازی logic در CMS service
|
||||||
|
// 3. تکمیل این handler
|
||||||
|
|
||||||
|
throw new NotImplementedException(
|
||||||
|
"Transfer Balance functionality is not yet implemented in CMS. " +
|
||||||
|
"Please add TransferBalance RPC to userwallet.proto first.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,17 +19,23 @@ public class
|
|||||||
public async Task<GetAllUserWalletChangeLogResponseDto> Handle(GetAllUserWalletChangeLogQuery request,
|
public async Task<GetAllUserWalletChangeLogResponseDto> Handle(GetAllUserWalletChangeLogQuery request,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var filter = new GetAllUserWalletChangeLogByFilterFilter();
|
||||||
|
|
||||||
|
if (_currentUserService.UserId.HasValue)
|
||||||
|
filter.UserId = _currentUserService.UserId.Value;
|
||||||
|
|
||||||
|
if (request.ReferenceId.HasValue)
|
||||||
|
filter.RefrenceId = request.ReferenceId.Value;
|
||||||
|
|
||||||
|
if (request.IsIncrease.HasValue)
|
||||||
|
filter.IsIncrease = request.IsIncrease.Value;
|
||||||
|
|
||||||
var result = await _context.UserWalletChangeLog.GetAllUserWalletChangeLogByFilterAsync(
|
var result = await _context.UserWalletChangeLog.GetAllUserWalletChangeLogByFilterAsync(
|
||||||
new GetAllUserWalletChangeLogByFilterRequest()
|
new GetAllUserWalletChangeLogByFilterRequest()
|
||||||
{
|
{
|
||||||
Filter = new GetAllUserWalletChangeLogByFilterFilter()
|
Filter = filter
|
||||||
{
|
|
||||||
UserId = _currentUserService.UserId.Value,
|
|
||||||
RefrenceId = request.ReferenceId.HasValue ? new Google.Protobuf.WellKnownTypes.Int64Value { Value = request.ReferenceId.Value } : null,
|
|
||||||
IsIncrease = request.IsIncrease.HasValue ? new Google.Protobuf.WellKnownTypes.BoolValue { Value = request.IsIncrease.Value } : null
|
|
||||||
}
|
|
||||||
}, cancellationToken: cancellationToken);
|
}, cancellationToken: cancellationToken);
|
||||||
var finalResult= result.Adapt<GetAllUserWalletChangeLogResponseDto>();
|
var finalResult = result.Adapt<GetAllUserWalletChangeLogResponseDto>();
|
||||||
return finalResult;
|
return finalResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ public class GetUserWithdrawalsQueryHandler : IRequestHandler<GetUserWithdrawals
|
|||||||
{
|
{
|
||||||
var response = await _context.Commission.GetUserCommissionPayoutsAsync(new GetUserCommissionPayoutsRequest()
|
var response = await _context.Commission.GetUserCommissionPayoutsAsync(new GetUserCommissionPayoutsRequest()
|
||||||
{
|
{
|
||||||
UserId = _currentUserService.UserId,
|
UserId = _currentUserService.UserId, // long? type - assign directly
|
||||||
Status = request.Status.HasValue ? new Google.Protobuf.WellKnownTypes.Int32Value { Value = request.Status.Value } : null,
|
Status = request.Status, // int? type - assign directly
|
||||||
PageIndex = 1,
|
PageIndex = 1,
|
||||||
PageSize = 50
|
PageSize = 50
|
||||||
}, cancellationToken: cancellationToken);
|
}, cancellationToken: cancellationToken);
|
||||||
@@ -33,7 +33,7 @@ public class GetUserWithdrawalsQueryHandler : IRequestHandler<GetUserWithdrawals
|
|||||||
WeekNumber = m.WeekNumber,
|
WeekNumber = m.WeekNumber,
|
||||||
TotalAmount = m.TotalAmount,
|
TotalAmount = m.TotalAmount,
|
||||||
Status = m.Status,
|
Status = m.Status,
|
||||||
WithdrawalMethod = m.WithdrawalMethod?.Value,
|
WithdrawalMethod = m.WithdrawalMethod, // int? type - no .Value needed
|
||||||
IbanNumber = m.IbanNumber,
|
IbanNumber = m.IbanNumber,
|
||||||
Created = m.Created.ToDateTime()
|
Created = m.Created.ToDateTime()
|
||||||
}).ToList()
|
}).ToList()
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using CMSMicroservice.Protobuf.Protos.Category;
|
using CMSMicroservice.Protobuf.Protos.Category;
|
||||||
using CMSMicroservice.Protobuf.Protos.OtpToken;
|
using CMSMicroservice.Protobuf.Protos.OtpToken;
|
||||||
using CMSMicroservice.Protobuf.Protos.Package;
|
using CMSMicroservice.Protobuf.Protos.Package;
|
||||||
using CMSMicroservice.Protobuf.Protos.PruductCategory;
|
using CMSMicroservice.Protobuf.Protos.ProductCategory;
|
||||||
using CMSMicroservice.Protobuf.Protos.Products;
|
using CMSMicroservice.Protobuf.Protos.Products;
|
||||||
using CMSMicroservice.Protobuf.Protos.ProductGallerys;
|
using CMSMicroservice.Protobuf.Protos.ProductGalleries;
|
||||||
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
using CMSMicroservice.Protobuf.Protos.ProductImages;
|
||||||
using CMSMicroservice.Protobuf.Protos.User;
|
using CMSMicroservice.Protobuf.Protos.User;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
using CMSMicroservice.Protobuf.Protos.UserAddress;
|
||||||
@@ -14,6 +14,8 @@ using CMSMicroservice.Protobuf.Protos.UserContract;
|
|||||||
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
using CMSMicroservice.Protobuf.Protos.UserOrder;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
using CMSMicroservice.Protobuf.Protos.UserWallet;
|
||||||
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
|
||||||
|
using CMSMicroservice.Protobuf.Protos.ClubMembership;
|
||||||
|
using CMSMicroservice.Protobuf.Protos.NetworkMembership;
|
||||||
using FrontOffice.BFF.Application.Common.Interfaces;
|
using FrontOffice.BFF.Application.Common.Interfaces;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using PYMSMicroservice.Protobuf.Protos.Transaction;
|
using PYMSMicroservice.Protobuf.Protos.Transaction;
|
||||||
@@ -53,10 +55,10 @@ public class ApplicationContractContext : IApplicationContractContext
|
|||||||
#region CMS
|
#region CMS
|
||||||
public PackageContract.PackageContractClient Package => GetService<PackageContract.PackageContractClient>();
|
public PackageContract.PackageContractClient Package => GetService<PackageContract.PackageContractClient>();
|
||||||
public ProductsContract.ProductsContractClient Product => GetService<ProductsContract.ProductsContractClient>();
|
public ProductsContract.ProductsContractClient Product => GetService<ProductsContract.ProductsContractClient>();
|
||||||
public ProductGallerysContract.ProductGallerysContractClient ProductGallerys => GetService<ProductGallerysContract.ProductGallerysContractClient>();
|
public ProductGalleriesContract.ProductGalleriesContractClient ProductGalleries => GetService<ProductGalleriesContract.ProductGalleriesContractClient>();
|
||||||
public ProductImagesContract.ProductImagesContractClient ProductImages => GetService<ProductImagesContract.ProductImagesContractClient>();
|
public ProductImagesContract.ProductImagesContractClient ProductImages => GetService<ProductImagesContract.ProductImagesContractClient>();
|
||||||
public CategoryContract.CategoryContractClient Category => GetService<CategoryContract.CategoryContractClient>();
|
public CategoryContract.CategoryContractClient Category => GetService<CategoryContract.CategoryContractClient>();
|
||||||
public PruductCategoryContract.PruductCategoryContractClient ProductCategory => GetService<PruductCategoryContract.PruductCategoryContractClient>();
|
public ProductCategoryContract.ProductCategoryContractClient ProductCategory => GetService<ProductCategoryContract.ProductCategoryContractClient>();
|
||||||
public UserCartsContract.UserCartsContractClient UserCart => GetService<UserCartsContract.UserCartsContractClient>();
|
public UserCartsContract.UserCartsContractClient UserCart => GetService<UserCartsContract.UserCartsContractClient>();
|
||||||
|
|
||||||
public UserContract.UserContractClient User => GetService<UserContract.UserContractClient>();
|
public UserContract.UserContractClient User => GetService<UserContract.UserContractClient>();
|
||||||
@@ -70,6 +72,10 @@ public class ApplicationContractContext : IApplicationContractContext
|
|||||||
public UserWalletChangeLogContract.UserWalletChangeLogContractClient UserWalletChangeLog => GetService<UserWalletChangeLogContract.UserWalletChangeLogContractClient>();
|
public UserWalletChangeLogContract.UserWalletChangeLogContractClient UserWalletChangeLog => GetService<UserWalletChangeLogContract.UserWalletChangeLogContractClient>();
|
||||||
public ConfigurationContract.ConfigurationContractClient Configuration => GetService<ConfigurationContract.ConfigurationContractClient>();
|
public ConfigurationContract.ConfigurationContractClient Configuration => GetService<ConfigurationContract.ConfigurationContractClient>();
|
||||||
public CommissionContract.CommissionContractClient Commission => GetService<CommissionContract.CommissionContractClient>();
|
public CommissionContract.CommissionContractClient Commission => GetService<CommissionContract.CommissionContractClient>();
|
||||||
|
|
||||||
|
// Network & Club System
|
||||||
|
public ClubMembershipContract.ClubMembershipContractClient ClubMemberships => GetService<ClubMembershipContract.ClubMembershipContractClient>();
|
||||||
|
public NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships => GetService<NetworkMembershipContract.NetworkMembershipContractClient>();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PYMS
|
#region PYMS
|
||||||
|
|||||||
38
src/FrontOffice.BFF.WebApi/Services/ClubMembershipService.cs
Normal file
38
src/FrontOffice.BFF.WebApi/Services/ClubMembershipService.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using FrontOffice.BFF.WebApi.Common.Services;
|
||||||
|
using FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
|
||||||
|
using FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
|
||||||
|
|
||||||
|
namespace FrontOffice.BFF.WebApi.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// سرویس باشگاه مشتریان - مختص کاربر جاری
|
||||||
|
/// این سرویس فعلاً از REST API استفاده میکند تا proto فایل برایش ایجاد شود
|
||||||
|
/// TODO: ایجاد proto فایل و تبدیل به gRPC service
|
||||||
|
/// </summary>
|
||||||
|
public class ClubMembershipService
|
||||||
|
{
|
||||||
|
private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
|
||||||
|
|
||||||
|
public ClubMembershipService(IDispatchRequestToCQRS dispatchRequestToCQRS)
|
||||||
|
{
|
||||||
|
_dispatchRequestToCQRS = dispatchRequestToCQRS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دریافت وضعیت عضویت باشگاه کاربر جاری
|
||||||
|
/// </summary>
|
||||||
|
public async Task<GetMyClubMembershipResponseDto> GetMyClubMembership(Empty request, ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<GetMyClubMembershipQuery, GetMyClubMembershipResponseDto>(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// فعالسازی عضویت باشگاه (پرداخت 56M)
|
||||||
|
/// </summary>
|
||||||
|
public async Task<ActivateMyClubMembershipResponseDto> ActivateMyClubMembership(
|
||||||
|
ActivateMyClubMembershipCommand request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
return await _dispatchRequestToCQRS.Handle<ActivateMyClubMembershipCommand, ActivateMyClubMembershipResponseDto>(request, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user