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(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.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
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
<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.Category.Protobuf\FrontOffice.BFF.Category.Protobuf.csproj" />
|
||||
<!-- CMS Protobuf for Commission, ClubMembership, NetworkMembership, Configuration -->
|
||||
<ProjectReference Include="..\..\..\CMS\src\CMSMicroservice.Protobuf\CMSMicroservice.Protobuf.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</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.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<GetProductsQuery, GetProductsResponseDto>
|
||||
@@ -28,10 +28,10 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, GetProd
|
||||
|
||||
var dto = response.Adapt<GetProductsResponseDto>();
|
||||
|
||||
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<GetProductsQuery, GetProd
|
||||
var categoryLookup = categoriesResponse.Models?
|
||||
.ToDictionary(c => c.Id) ?? new Dictionary<long, CMSCategory.GetAllCategoryByFilterResponseModel>();
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
using CMSMicroservice.Protobuf.Protos.User;
|
||||
|
||||
namespace FrontOffice.BFF.Application.UserCQ.Commands.DeleteUser;
|
||||
public class DeleteUserCommandHandler : IRequestHandler<DeleteUserCommand, Unit>
|
||||
{
|
||||
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<Unit> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
namespace FrontOffice.BFF.Application.UserWalletCQ.Commands.TransferUserWalletBallance;
|
||||
|
||||
/// <summary>
|
||||
/// انتقال موجودی کیف پول - نیاز به پیادهسازی در CMS
|
||||
/// TODO: این قابلیت نیاز به افزودن rpc TransferBalance در userwallet.proto دارد
|
||||
/// </summary>
|
||||
public class TransferUserWalletBallanceCommandHandler : IRequestHandler<TransferUserWalletBallanceCommand, Unit>
|
||||
{
|
||||
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<Unit> 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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,15 +19,21 @@ public class
|
||||
public async Task<GetAllUserWalletChangeLogResponseDto> 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<GetAllUserWalletChangeLogResponseDto>();
|
||||
return finalResult;
|
||||
|
||||
@@ -17,8 +17,8 @@ public class GetUserWithdrawalsQueryHandler : IRequestHandler<GetUserWithdrawals
|
||||
{
|
||||
var response = await _context.Commission.GetUserCommissionPayoutsAsync(new GetUserCommissionPayoutsRequest()
|
||||
{
|
||||
UserId = _currentUserService.UserId,
|
||||
Status = request.Status.HasValue ? new Google.Protobuf.WellKnownTypes.Int32Value { Value = request.Status.Value } : null,
|
||||
UserId = _currentUserService.UserId, // long? type - assign directly
|
||||
Status = request.Status, // int? type - assign directly
|
||||
PageIndex = 1,
|
||||
PageSize = 50
|
||||
}, cancellationToken: cancellationToken);
|
||||
@@ -33,7 +33,7 @@ public class GetUserWithdrawalsQueryHandler : IRequestHandler<GetUserWithdrawals
|
||||
WeekNumber = m.WeekNumber,
|
||||
TotalAmount = m.TotalAmount,
|
||||
Status = m.Status,
|
||||
WithdrawalMethod = m.WithdrawalMethod?.Value,
|
||||
WithdrawalMethod = m.WithdrawalMethod, // int? type - no .Value needed
|
||||
IbanNumber = m.IbanNumber,
|
||||
Created = m.Created.ToDateTime()
|
||||
}).ToList()
|
||||
|
||||
@@ -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 FrontOffice.BFF.Application.Common.Interfaces;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PYMSMicroservice.Protobuf.Protos.Transaction;
|
||||
@@ -53,10 +55,10 @@ public class ApplicationContractContext : IApplicationContractContext
|
||||
#region CMS
|
||||
public PackageContract.PackageContractClient Package => GetService<PackageContract.PackageContractClient>();
|
||||
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 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 UserContract.UserContractClient User => GetService<UserContract.UserContractClient>();
|
||||
@@ -70,6 +72,10 @@ public class ApplicationContractContext : IApplicationContractContext
|
||||
public UserWalletChangeLogContract.UserWalletChangeLogContractClient UserWalletChangeLog => GetService<UserWalletChangeLogContract.UserWalletChangeLogContractClient>();
|
||||
public ConfigurationContract.ConfigurationContractClient Configuration => GetService<ConfigurationContract.ConfigurationContractClient>();
|
||||
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
|
||||
|
||||
#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