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); + } +}