diff --git a/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipCommand.cs b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipCommand.cs
new file mode 100644
index 0000000..c03071b
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipCommand.cs
@@ -0,0 +1,22 @@
+namespace FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
+
+///
+/// فعالسازی عضویت باشگاه کاربر جاری (پرداخت 56M)
+///
+public record ActivateMyClubMembershipCommand : IRequest
+{
+ ///
+ /// شناسه پکیج (PackageId)
+ ///
+ public long PackageId { get; init; }
+
+ ///
+ /// کد فعالسازی (اختیاری)
+ ///
+ public string? ActivationCode { get; init; }
+
+ ///
+ /// مدت زمان عضویت به ماه (پیشفرض: 12)
+ ///
+ public int DurationMonths { get; init; } = 12;
+}
diff --git a/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipCommandHandler.cs b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipCommandHandler.cs
new file mode 100644
index 0000000..542ef33
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipCommandHandler.cs
@@ -0,0 +1,51 @@
+using CMSMicroservice.Protobuf.Protos.ClubMembership;
+
+namespace FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
+
+public class ActivateMyClubMembershipCommandHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
+
+ public ActivateMyClubMembershipCommandHandler(
+ IApplicationContractContext context,
+ ICurrentUserService currentUserService)
+ {
+ _context = context;
+ _currentUserService = currentUserService;
+ }
+
+ public async Task 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 تومان
+ };
+ }
+}
diff --git a/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipResponseDto.cs b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipResponseDto.cs
new file mode 100644
index 0000000..c6b143d
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Commands/ActivateMyClubMembership/ActivateMyClubMembershipResponseDto.cs
@@ -0,0 +1,29 @@
+namespace FrontOffice.BFF.Application.ClubMembershipCQ.Commands.ActivateMyClubMembership;
+
+public class ActivateMyClubMembershipResponseDto
+{
+ ///
+ /// آیا فعالسازی موفق بود؟
+ ///
+ public bool Success { get; set; }
+
+ ///
+ /// پیام نتیجه
+ ///
+ public string Message { get; set; } = string.Empty;
+
+ ///
+ /// تاریخ فعالسازی
+ ///
+ public DateTime ActivationDate { get; set; }
+
+ ///
+ /// تاریخ انقضا
+ ///
+ public DateTime ExpirationDate { get; set; }
+
+ ///
+ /// مبلغ پرداخت شده
+ ///
+ public long AmountPaid { get; set; }
+}
diff --git a/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipQuery.cs b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipQuery.cs
new file mode 100644
index 0000000..6500251
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipQuery.cs
@@ -0,0 +1,6 @@
+namespace FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
+
+///
+/// دریافت وضعیت عضویت باشگاه کاربر جاری
+///
+public record GetMyClubMembershipQuery : IRequest;
diff --git a/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipQueryHandler.cs b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipQueryHandler.cs
new file mode 100644
index 0000000..458e3fb
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipQueryHandler.cs
@@ -0,0 +1,65 @@
+using CMSMicroservice.Protobuf.Protos.ClubMembership;
+
+namespace FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
+
+public class GetMyClubMembershipQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
+
+ public GetMyClubMembershipQueryHandler(
+ IApplicationContractContext context,
+ ICurrentUserService currentUserService)
+ {
+ _context = context;
+ _currentUserService = currentUserService;
+ }
+
+ public async Task 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";
+ }
+}
diff --git a/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipResponseDto.cs b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipResponseDto.cs
new file mode 100644
index 0000000..a22c9b0
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/ClubMembershipCQ/Queries/GetMyClubMembership/GetMyClubMembershipResponseDto.cs
@@ -0,0 +1,54 @@
+namespace FrontOffice.BFF.Application.ClubMembershipCQ.Queries.GetMyClubMembership;
+
+public class GetMyClubMembershipResponseDto
+{
+ ///
+ /// شناسه کاربر
+ ///
+ public long UserId { get; set; }
+
+ ///
+ /// شناسه پکیج
+ ///
+ public long PackageId { get; set; }
+
+ ///
+ /// نام پکیج
+ ///
+ public string PackageName { get; set; } = string.Empty;
+
+ ///
+ /// کد فعالسازی
+ ///
+ public string ActivationCode { get; set; } = string.Empty;
+
+ ///
+ /// وضعیت فعال/غیرفعال
+ ///
+ public bool IsActive { get; set; }
+
+ ///
+ /// تاریخ فعالسازی (mapped from ActivatedAt)
+ ///
+ public DateTime? ActivationDate { get; set; }
+
+ ///
+ /// تاریخ انقضا (mapped from ExpiresAt)
+ ///
+ public DateTime? ExpirationDate { get; set; }
+
+ ///
+ /// نوع عضویت (Trial/Active/Expired/Inactive)
+ ///
+ public string Status { get; set; } = string.Empty;
+
+ ///
+ /// تعداد روزهای باقیمانده
+ ///
+ public int DaysRemaining { get; set; }
+
+ ///
+ /// آیا در دوره آزمایشی است؟
+ ///
+ public bool IsTrialPeriod { get; set; }
+}
diff --git a/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsQuery.cs b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsQuery.cs
new file mode 100644
index 0000000..576de8c
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsQuery.cs
@@ -0,0 +1,27 @@
+namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
+
+///
+/// دریافت لیست پرداختهای کمیسیون کاربر جاری
+///
+public record GetMyCommissionPayoutsQuery : IRequest
+{
+ ///
+ /// شماره هفته در فرمت ISO (مثال: "2025-W48"، null = همه)
+ ///
+ public string? WeekNumber { get; init; }
+
+ ///
+ /// وضعیت: 0=Pending, 1=Calculated, 2=Paid, 3=Withdrawn (null = همه)
+ ///
+ public int? Status { get; init; }
+
+ ///
+ /// شماره صفحه (1-based, internally converted to 0-based PageIndex)
+ ///
+ public int PageNumber { get; init; } = 1;
+
+ ///
+ /// تعداد در صفحه
+ ///
+ public int PageSize { get; init; } = 20;
+}
diff --git a/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsQueryHandler.cs b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsQueryHandler.cs
new file mode 100644
index 0000000..b7e9af7
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsQueryHandler.cs
@@ -0,0 +1,97 @@
+using CMSMicroservice.Protobuf.Protos.Commission;
+
+namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
+
+public class GetMyCommissionPayoutsQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
+
+ public GetMyCommissionPayoutsQueryHandler(
+ IApplicationContractContext context,
+ ICurrentUserService currentUserService)
+ {
+ _context = context;
+ _currentUserService = currentUserService;
+ }
+
+ public async Task 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");
+ }
+}
diff --git a/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsResponseDto.cs b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsResponseDto.cs
new file mode 100644
index 0000000..aa554f8
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyCommissionPayouts/GetMyCommissionPayoutsResponseDto.cs
@@ -0,0 +1,62 @@
+namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
+
+public class GetMyCommissionPayoutsResponseDto
+{
+ public List Payouts { get; set; } = new();
+ public int TotalCount { get; set; }
+ public int PageNumber { get; set; }
+ public int PageSize { get; set; }
+}
+
+public class CommissionPayoutDto
+{
+ ///
+ /// شناسه
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// شماره هفته (e.g., "2024-W45")
+ ///
+ public string WeekNumber { get; set; } = string.Empty;
+
+ ///
+ /// لیبل هفته (هفته 45 - آذر 1403)
+ ///
+ public string WeekLabel { get; set; } = string.Empty;
+
+ ///
+ /// تعداد Balance کسب شده
+ ///
+ public int BalancesEarned { get; set; }
+
+ ///
+ /// مبلغ کل
+ ///
+ public long TotalAmount { get; set; }
+
+ ///
+ /// مبلغ فرمت شده
+ ///
+ public string AmountFormatted { get; set; } = string.Empty;
+
+ ///
+ /// وضعیت (Pending/Calculated/Paid/Withdrawn)
+ ///
+ public string Status { get; set; } = string.Empty;
+
+ ///
+ /// رنگ Badge
+ ///
+ public string StatusBadgeColor { get; set; } = string.Empty;
+
+ ///
+ /// تاریخ محاسبه
+ ///
+ public DateTime CalculatedDate { get; set; }
+
+ ///
+ /// تاریخ شمسی
+ ///
+ public string DatePersian { get; set; } = string.Empty;
+}
diff --git a/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQuery.cs b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQuery.cs
new file mode 100644
index 0000000..bc5eb0b
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQuery.cs
@@ -0,0 +1,27 @@
+namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
+
+///
+/// دریافت تعادل هفتگی کاربر جاری
+///
+public record GetMyWeeklyBalancesQuery : IRequest
+{
+ ///
+ /// شماره هفته در فرمت ISO (مثال: "2025-W48"، null = هفته جاری)
+ ///
+ public string? WeekNumber { get; init; }
+
+ ///
+ /// فقط تعادلهای فعال (غیر منقضی)
+ ///
+ public bool OnlyActive { get; init; } = true;
+
+ ///
+ /// شماره صفحه (1-based)
+ ///
+ public int PageNumber { get; init; } = 1;
+
+ ///
+ /// تعداد در صفحه
+ ///
+ public int PageSize { get; init; } = 10;
+}
diff --git a/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQueryHandler.cs b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQueryHandler.cs
new file mode 100644
index 0000000..4b7e8f7
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQueryHandler.cs
@@ -0,0 +1,66 @@
+using CMSMicroservice.Protobuf.Protos.Commission;
+
+namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
+
+public class GetMyWeeklyBalancesQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
+
+ public GetMyWeeklyBalancesQueryHandler(
+ IApplicationContractContext context,
+ ICurrentUserService currentUserService)
+ {
+ _context = context;
+ _currentUserService = currentUserService;
+ }
+
+ public async Task 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
+ };
+ }
+}
diff --git a/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesResponseDto.cs b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesResponseDto.cs
new file mode 100644
index 0000000..f28fe2f
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesResponseDto.cs
@@ -0,0 +1,82 @@
+namespace FrontOffice.BFF.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
+
+public class GetMyWeeklyBalancesResponseDto
+{
+ ///
+ /// لیست تعادلهای هفتگی
+ ///
+ public List Balances { get; set; } = new();
+
+ ///
+ /// تعداد کل رکوردها
+ ///
+ public int TotalCount { get; set; }
+
+ ///
+ /// شماره صفحه
+ ///
+ public int PageNumber { get; set; }
+
+ ///
+ /// تعداد در صفحه
+ ///
+ public int PageSize { get; set; }
+
+ ///
+ /// مجموع تعادل پای چپ
+ ///
+ public int TotalLeftBalances { get; set; }
+
+ ///
+ /// مجموع تعادل پای راست
+ ///
+ public int TotalRightBalances { get; set; }
+
+ ///
+ /// پای ضعیفتر (Left/Right)
+ ///
+ public string WeakerLeg { get; set; } = string.Empty;
+}
+
+public class WeeklyBalanceItemDto
+{
+ ///
+ /// شناسه رکورد
+ ///
+ public long Id { get; set; }
+
+ ///
+ /// شماره هفته (فرمت: "2025-W48")
+ ///
+ public string WeekNumber { get; set; } = string.Empty;
+
+ ///
+ /// تعادل پای چپ
+ ///
+ public int LeftLegBalances { get; set; }
+
+ ///
+ /// تعادل پای راست
+ ///
+ public int RightLegBalances { get; set; }
+
+ ///
+ /// مجموع تعادل
+ ///
+ public int TotalBalances { get; set; }
+
+ ///
+ /// سهم از استخر هفتگی
+ ///
+ public long WeeklyPoolContribution { get; set; }
+
+ ///
+ /// تاریخ محاسبه
+ ///
+ public DateTime? CalculatedAt { get; set; }
+
+ ///
+ /// آیا منقضی شده؟
+ ///
+ public bool IsExpired { get; set; }
+}
diff --git a/src/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs b/src/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs
index 590d946..e7178fd 100644
--- a/src/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs
+++ b/src/FrontOffice.BFF.Application/Common/Exceptions/ForbiddenAccessException.cs
@@ -5,4 +5,12 @@ public class ForbiddenAccessException : Exception
public ForbiddenAccessException() : base()
{
}
+
+ public ForbiddenAccessException(string message) : base(message)
+ {
+ }
+
+ public ForbiddenAccessException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
}
diff --git a/src/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs b/src/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs
index 3bd6ae9..89c0c14 100644
--- a/src/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs
+++ b/src/FrontOffice.BFF.Application/Common/Interfaces/IApplicationContractContext.cs
@@ -1,9 +1,9 @@
using CMSMicroservice.Protobuf.Protos.Category;
using CMSMicroservice.Protobuf.Protos.OtpToken;
using CMSMicroservice.Protobuf.Protos.Package;
-using CMSMicroservice.Protobuf.Protos.PruductCategory;
+using CMSMicroservice.Protobuf.Protos.ProductCategory;
using CMSMicroservice.Protobuf.Protos.Products;
-using CMSMicroservice.Protobuf.Protos.ProductGallerys;
+using CMSMicroservice.Protobuf.Protos.ProductGalleries;
using CMSMicroservice.Protobuf.Protos.ProductImages;
using CMSMicroservice.Protobuf.Protos.User;
using CMSMicroservice.Protobuf.Protos.UserAddress;
@@ -14,6 +14,8 @@ using CMSMicroservice.Protobuf.Protos.UserContract;
using CMSMicroservice.Protobuf.Protos.UserOrder;
using CMSMicroservice.Protobuf.Protos.UserWallet;
using CMSMicroservice.Protobuf.Protos.UserWalletChangeLog;
+using CMSMicroservice.Protobuf.Protos.ClubMembership;
+using CMSMicroservice.Protobuf.Protos.NetworkMembership;
using PYMSMicroservice.Protobuf.Protos.Transaction;
namespace FrontOffice.BFF.Application.Common.Interfaces;
@@ -29,10 +31,10 @@ public interface IApplicationContractContext
#region CMS
PackageContract.PackageContractClient Package { get; }
ProductsContract.ProductsContractClient Product { get; }
- ProductGallerysContract.ProductGallerysContractClient ProductGallerys { get; }
+ ProductGalleriesContract.ProductGalleriesContractClient ProductGalleries { get; }
ProductImagesContract.ProductImagesContractClient ProductImages { get; }
CategoryContract.CategoryContractClient Category { get; }
- PruductCategoryContract.PruductCategoryContractClient ProductCategory { get; }
+ ProductCategoryContract.ProductCategoryContractClient ProductCategory { get; }
UserCartsContract.UserCartsContractClient UserCart { get; }
UserContract.UserContractClient User { get; }
UserContractContract.UserContractContractClient UserContract { get; }
@@ -43,6 +45,10 @@ public interface IApplicationContractContext
UserWalletChangeLogContract.UserWalletChangeLogContractClient UserWalletChangeLog { get; }
ConfigurationContract.ConfigurationContractClient Configuration { get; }
CommissionContract.CommissionContractClient Commission { get; }
+
+ // Network & Club System
+ ClubMembershipContract.ClubMembershipContractClient ClubMemberships { get; }
+ NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships { get; }
#endregion
#region PYMS
diff --git a/src/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj b/src/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj
index 637e28f..bd67f4d 100644
--- a/src/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj
+++ b/src/FrontOffice.BFF.Application/FrontOffice.BFF.Application.csproj
@@ -15,6 +15,8 @@
+
+
diff --git a/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsQuery.cs b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsQuery.cs
new file mode 100644
index 0000000..b9a81d3
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsQuery.cs
@@ -0,0 +1,6 @@
+namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
+
+///
+/// دریافت آمار شبکه کاربر جاری
+///
+public record GetMyNetworkStatisticsQuery : IRequest;
diff --git a/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsQueryHandler.cs b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsQueryHandler.cs
new file mode 100644
index 0000000..8e15fd9
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsQueryHandler.cs
@@ -0,0 +1,65 @@
+using CMSMicroservice.Protobuf.Protos.NetworkMembership;
+
+namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
+
+public class GetMyNetworkStatisticsQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
+
+ public GetMyNetworkStatisticsQueryHandler(
+ IApplicationContractContext context,
+ ICurrentUserService currentUserService)
+ {
+ _context = context;
+ _currentUserService = currentUserService;
+ }
+
+ public async Task 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
+ };
+ }
+}
diff --git a/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsResponseDto.cs b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsResponseDto.cs
new file mode 100644
index 0000000..356b138
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkStatistics/GetMyNetworkStatisticsResponseDto.cs
@@ -0,0 +1,77 @@
+namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics;
+
+public class GetMyNetworkStatisticsResponseDto
+{
+ ///
+ /// تعداد کل اعضا
+ ///
+ public int TotalMembers { get; set; }
+
+ ///
+ /// تعداد اعضای فعال
+ ///
+ public int ActiveMembers { get; set; }
+
+ ///
+ /// تعداد اعضای پای چپ
+ ///
+ public int LeftLegCount { get; set; }
+
+ ///
+ /// تعداد اعضای پای راست
+ ///
+ public int RightLegCount { get; set; }
+
+ ///
+ /// درصد پای چپ
+ ///
+ public double LeftPercentage { get; set; }
+
+ ///
+ /// درصد پای راست
+ ///
+ public double RightPercentage { get; set; }
+
+ ///
+ /// میانگین عمق درخت
+ ///
+ public double AverageDepth { get; set; }
+
+ ///
+ /// حداکثر عمق درخت
+ ///
+ public int MaxDepth { get; set; }
+
+ ///
+ /// پای ضعیفتر (Weaker Leg)
+ ///
+ public string WeakerLeg { get; set; } = string.Empty;
+
+ ///
+ /// سطح کاربر در شبکه
+ ///
+ public int MyNetworkLevel { get; set; }
+
+ ///
+ /// پای کاربر در شبکه (Left/Right)
+ ///
+ public string MyNetworkLeg { get; set; } = string.Empty;
+
+ ///
+ /// کد معرفی کاربر
+ ///
+ public string MyReferralCode { get; set; } = string.Empty;
+
+ ///
+ /// آخرین عضو اضافه شده
+ ///
+ 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; }
+}
diff --git a/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeQuery.cs b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeQuery.cs
new file mode 100644
index 0000000..b1ebd0b
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeQuery.cs
@@ -0,0 +1,12 @@
+namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
+
+///
+/// دریافت درخت شبکه باینری کاربر جاری
+///
+public record GetMyNetworkTreeQuery : IRequest
+{
+ ///
+ /// حداکثر عمق درخت (1-10)
+ ///
+ public int MaxDepth { get; init; } = 3;
+}
diff --git a/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeQueryHandler.cs b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeQueryHandler.cs
new file mode 100644
index 0000000..1fb1765
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeQueryHandler.cs
@@ -0,0 +1,94 @@
+using CMSMicroservice.Protobuf.Protos.NetworkMembership;
+
+namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
+
+public class GetMyNetworkTreeQueryHandler : IRequestHandler
+{
+ private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
+
+ public GetMyNetworkTreeQueryHandler(
+ IApplicationContractContext context,
+ ICurrentUserService currentUserService)
+ {
+ _context = context;
+ _currentUserService = currentUserService;
+ }
+
+ public async Task 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)
+ };
+ }
+
+ ///
+ /// Build hierarchical tree from flat list returned by CMS
+ ///
+ private NetworkNodeDto? BuildTreeFromFlatList(List 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 allNodes,
+ Dictionary 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));
+ }
+}
diff --git a/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeResponseDto.cs b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeResponseDto.cs
new file mode 100644
index 0000000..c3e0c51
--- /dev/null
+++ b/src/FrontOffice.BFF.Application/NetworkMembershipCQ/Queries/GetMyNetworkTree/GetMyNetworkTreeResponseDto.cs
@@ -0,0 +1,67 @@
+namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree;
+
+public class GetMyNetworkTreeResponseDto
+{
+ ///
+ /// نود ریشه (کاربر جاری)
+ ///
+ public NetworkNodeDto? RootNode { get; set; }
+
+ ///
+ /// تعداد کل اعضا در درخت
+ ///
+ public int TotalMembers { get; set; }
+
+ ///
+ /// عمق فعلی درخت
+ ///
+ public int CurrentDepth { get; set; }
+}
+
+public class NetworkNodeDto
+{
+ ///
+ /// شناسه کاربر
+ ///
+ public long UserId { get; set; }
+
+ ///
+ /// نام کاربر
+ ///
+ public string FullName { get; set; } = string.Empty;
+
+ ///
+ /// موبایل
+ ///
+ public string Mobile { get; set; } = string.Empty;
+
+ ///
+ /// آواتار
+ ///
+ public string? Avatar { get; set; }
+
+ ///
+ /// موقعیت در درخت (Root/Left/Right)
+ ///
+ public string Position { get; set; } = string.Empty;
+
+ ///
+ /// فرزند چپ
+ ///
+ public NetworkNodeDto? LeftChild { get; set; }
+
+ ///
+ /// فرزند راست
+ ///
+ public NetworkNodeDto? RightChild { get; set; }
+
+ ///
+ /// سطح در درخت (0 = root)
+ ///
+ public int Level { get; set; }
+
+ ///
+ /// آیا فرزند دارد؟
+ ///
+ public bool HasChildren => LeftChild != null || RightChild != null;
+}
diff --git a/src/FrontOffice.BFF.Application/ProductsCQ/Queries/GetProducts/GetProductsQueryHandler.cs b/src/FrontOffice.BFF.Application/ProductsCQ/Queries/GetProducts/GetProductsQueryHandler.cs
index 2fbe452..0b0bc84 100644
--- a/src/FrontOffice.BFF.Application/ProductsCQ/Queries/GetProducts/GetProductsQueryHandler.cs
+++ b/src/FrontOffice.BFF.Application/ProductsCQ/Queries/GetProducts/GetProductsQueryHandler.cs
@@ -1,10 +1,10 @@
using System.Collections.Generic;
using System.Linq;
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.Products;
-using CMSPruductCategory = CMSMicroservice.Protobuf.Protos.PruductCategory;
+using CMSProductCategory = CMSMicroservice.Protobuf.Protos.ProductCategory;
namespace FrontOffice.BFF.Application.ProductsCQ.Queries.GetProducts;
public class GetProductsQueryHandler : IRequestHandler
@@ -28,10 +28,10 @@ public class GetProductsQueryHandler : IRequestHandler();
- var galleryResponse = await _context.ProductGallerys.GetAllProductGallerysByFilterAsync(
- new GetAllProductGallerysByFilterRequest
+ var galleryResponse = await _context.ProductGalleries.GetAllProductGalleriesByFilterAsync(
+ new GetAllProductGalleriesByFilterRequest
{
- Filter = new GetAllProductGallerysByFilterFilter()
+ Filter = new GetAllProductGalleriesByFilterFilter()
}, cancellationToken: cancellationToken);
var relatedItems = galleryResponse?.Models?.Where(x => x.ProductId == request.Id).ToList();
@@ -82,10 +82,10 @@ public class GetProductsQueryHandler : IRequestHandler c.Id) ?? new Dictionary();
- var productCategoryResponse = await _context.ProductCategory.GetAllPruductCategoryByFilterAsync(
- new CMSPruductCategory.GetAllPruductCategoryByFilterRequest
+ var productCategoryResponse = await _context.ProductCategory.GetAllProductCategoryByFilterAsync(
+ new CMSProductCategory.GetAllProductCategoryByFilterRequest
{
- Filter = new CMSPruductCategory.GetAllPruductCategoryByFilterFilter
+ Filter = new CMSProductCategory.GetAllProductCategoryByFilterFilter
{
ProductId = productId
},
diff --git a/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs
index 5b9b2ad..02b4233 100644
--- a/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs
+++ b/src/FrontOffice.BFF.Application/UserCQ/Commands/DeleteUser/DeleteUserCommandHandler.cs
@@ -1,16 +1,32 @@
+using CMSMicroservice.Protobuf.Protos.User;
+
namespace FrontOffice.BFF.Application.UserCQ.Commands.DeleteUser;
public class DeleteUserCommandHandler : IRequestHandler
{
private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
- public DeleteUserCommandHandler(IApplicationContractContext context)
+ public DeleteUserCommandHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
{
_context = context;
+ _currentUserService = currentUserService;
}
public async Task Handle(DeleteUserCommand request, CancellationToken cancellationToken)
{
- //TODO: Implement your business logic
- return new Unit();
+ // Security check: User can only delete their own account
+ 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;
}
}
diff --git a/src/FrontOffice.BFF.Application/UserWalletCQ/Commands/TransferUserWalletBallance/TransferUserWalletBallanceCommandHandler.cs b/src/FrontOffice.BFF.Application/UserWalletCQ/Commands/TransferUserWalletBallance/TransferUserWalletBallanceCommandHandler.cs
index 5d065ba..63e7f4d 100644
--- a/src/FrontOffice.BFF.Application/UserWalletCQ/Commands/TransferUserWalletBallance/TransferUserWalletBallanceCommandHandler.cs
+++ b/src/FrontOffice.BFF.Application/UserWalletCQ/Commands/TransferUserWalletBallance/TransferUserWalletBallanceCommandHandler.cs
@@ -1,16 +1,29 @@
namespace FrontOffice.BFF.Application.UserWalletCQ.Commands.TransferUserWalletBallance;
+
+///
+/// انتقال موجودی کیف پول - نیاز به پیادهسازی در CMS
+/// TODO: این قابلیت نیاز به افزودن rpc TransferBalance در userwallet.proto دارد
+///
public class TransferUserWalletBallanceCommandHandler : IRequestHandler
{
private readonly IApplicationContractContext _context;
+ private readonly ICurrentUserService _currentUserService;
- public TransferUserWalletBallanceCommandHandler(IApplicationContractContext context)
+ public TransferUserWalletBallanceCommandHandler(IApplicationContractContext context, ICurrentUserService currentUserService)
{
_context = context;
+ _currentUserService = currentUserService;
}
public async Task Handle(TransferUserWalletBallanceCommand request, CancellationToken cancellationToken)
{
- //TODO: Implement your business logic
- return new Unit();
+ // TODO: این قابلیت نیاز به پیادهسازی در CMS دارد
+ // 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.");
}
}
diff --git a/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetAllUserWalletChangeLog/GetAllUserWalletChangeLogQueryHandler.cs b/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetAllUserWalletChangeLog/GetAllUserWalletChangeLogQueryHandler.cs
index 9decfed..291b3f4 100644
--- a/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetAllUserWalletChangeLog/GetAllUserWalletChangeLogQueryHandler.cs
+++ b/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetAllUserWalletChangeLog/GetAllUserWalletChangeLogQueryHandler.cs
@@ -19,17 +19,23 @@ public class
public async Task Handle(GetAllUserWalletChangeLogQuery request,
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(
new GetAllUserWalletChangeLogByFilterRequest()
{
- Filter = new GetAllUserWalletChangeLogByFilterFilter()
- {
- 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
- }
+ Filter = filter
}, cancellationToken: cancellationToken);
- var finalResult= result.Adapt();
+ var finalResult = result.Adapt();
return finalResult;
}
}
diff --git a/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetUserWithdrawals/GetUserWithdrawalsQueryHandler.cs b/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetUserWithdrawals/GetUserWithdrawalsQueryHandler.cs
index b9ac839..c04b299 100644
--- a/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetUserWithdrawals/GetUserWithdrawalsQueryHandler.cs
+++ b/src/FrontOffice.BFF.Application/UserWalletCQ/Queries/GetUserWithdrawals/GetUserWithdrawalsQueryHandler.cs
@@ -17,8 +17,8 @@ public class GetUserWithdrawalsQueryHandler : IRequestHandler GetService();
public ProductsContract.ProductsContractClient Product => GetService();
- public ProductGallerysContract.ProductGallerysContractClient ProductGallerys => GetService();
+ public ProductGalleriesContract.ProductGalleriesContractClient ProductGalleries => GetService();
public ProductImagesContract.ProductImagesContractClient ProductImages => GetService();
public CategoryContract.CategoryContractClient Category => GetService();
- public PruductCategoryContract.PruductCategoryContractClient ProductCategory => GetService();
+ public ProductCategoryContract.ProductCategoryContractClient ProductCategory => GetService();
public UserCartsContract.UserCartsContractClient UserCart => GetService();
public UserContract.UserContractClient User => GetService();
@@ -70,6 +72,10 @@ public class ApplicationContractContext : IApplicationContractContext
public UserWalletChangeLogContract.UserWalletChangeLogContractClient UserWalletChangeLog => GetService();
public ConfigurationContract.ConfigurationContractClient Configuration => GetService();
public CommissionContract.CommissionContractClient Commission => GetService();
+
+ // Network & Club System
+ public ClubMembershipContract.ClubMembershipContractClient ClubMemberships => GetService();
+ public NetworkMembershipContract.NetworkMembershipContractClient NetworkMemberships => GetService();
#endregion
#region PYMS
diff --git a/src/FrontOffice.BFF.WebApi/Services/ClubMembershipService.cs b/src/FrontOffice.BFF.WebApi/Services/ClubMembershipService.cs
new file mode 100644
index 0000000..dd9bd39
--- /dev/null
+++ b/src/FrontOffice.BFF.WebApi/Services/ClubMembershipService.cs
@@ -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;
+
+///
+/// سرویس باشگاه مشتریان - مختص کاربر جاری
+/// این سرویس فعلاً از REST API استفاده میکند تا proto فایل برایش ایجاد شود
+/// TODO: ایجاد proto فایل و تبدیل به gRPC service
+///
+public class ClubMembershipService
+{
+ private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS;
+
+ public ClubMembershipService(IDispatchRequestToCQRS dispatchRequestToCQRS)
+ {
+ _dispatchRequestToCQRS = dispatchRequestToCQRS;
+ }
+
+ ///
+ /// دریافت وضعیت عضویت باشگاه کاربر جاری
+ ///
+ public async Task GetMyClubMembership(Empty request, ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(context);
+ }
+
+ ///
+ /// فعالسازی عضویت باشگاه (پرداخت 56M)
+ ///
+ public async Task ActivateMyClubMembership(
+ ActivateMyClubMembershipCommand request,
+ ServerCallContext context)
+ {
+ return await _dispatchRequestToCQRS.Handle(request, context);
+ }
+}