diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembership/GetClubMembershipQueryHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembership/GetClubMembershipQueryHandler.cs index 2252d21..d9dd99e 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembership/GetClubMembershipQueryHandler.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Queries/GetClubMembership/GetClubMembershipQueryHandler.cs @@ -3,14 +3,18 @@ namespace CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembership public class GetClubMembershipQueryHandler : IRequestHandler { private readonly IApplicationDbContext _context; + private readonly ILogger _logger; - public GetClubMembershipQueryHandler(IApplicationDbContext context) + public GetClubMembershipQueryHandler(IApplicationDbContext context, ILogger logger) { _context = context; + _logger = logger; } public async Task Handle(GetClubMembershipQuery request, CancellationToken cancellationToken) { + _logger.LogInformation("GetClubMembership called for UserId: {UserId}", request.UserId); + var membership = await _context.ClubMemberships .AsNoTracking() .Where(x => x.UserId == request.UserId) @@ -27,6 +31,26 @@ public class GetClubMembershipQueryHandler : IRequestHandler +/// Query برای دریافت تعادل‌های هفتگی کاربر جاری (از JWT) +/// +public record GetMyWeeklyBalancesQuery : IRequest +{ + /// + /// شناسه تعریف هفته (اختیاری) + /// + public long? WeekDefinitionId { get; init; } + + /// + /// فقط موارد Expired نشده؟ + /// + public bool OnlyActive { get; init; } + + /// + /// Pagination + /// + public PaginationState? PaginationState { get; init; } +} diff --git a/src/CMSMicroservice.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQueryHandler.cs b/src/CMSMicroservice.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQueryHandler.cs new file mode 100644 index 0000000..ae27b89 --- /dev/null +++ b/src/CMSMicroservice.Application/CommissionCQ/Queries/GetMyWeeklyBalances/GetMyWeeklyBalancesQueryHandler.cs @@ -0,0 +1,47 @@ +using CMSMicroservice.Application.CommissionCQ.Queries.GetUserWeeklyBalances; + +namespace CMSMicroservice.Application.CommissionCQ.Queries.GetMyWeeklyBalances; + +/// +/// Handler برای دریافت تعادل‌های هفتگی کاربر جاری +/// +public class GetMyWeeklyBalancesQueryHandler : IRequestHandler +{ + private readonly ICurrentUserService _currentUserService; + private readonly IMediator _mediator; + private readonly ILogger _logger; + + public GetMyWeeklyBalancesQueryHandler( + ICurrentUserService currentUserService, + IMediator mediator, + ILogger logger) + { + _currentUserService = currentUserService; + _mediator = mediator; + _logger = logger; + } + + public async Task Handle(GetMyWeeklyBalancesQuery request, CancellationToken cancellationToken) + { + // دریافت UserId از JWT + if (!long.TryParse(_currentUserService.UserId, out var userId) || userId <= 0) + { + _logger.LogWarning("GetMyWeeklyBalances called without valid user authentication"); + throw new UnauthorizedAccessException("کاربر احراز هویت نشده است"); + } + + _logger.LogInformation("GetMyWeeklyBalances for UserId: {UserId}, WeekDefinitionId: {WeekDefinitionId}", + userId, request.WeekDefinitionId); + + // فراخوانی GetUserWeeklyBalancesQuery با UserId از JWT + var query = new GetUserWeeklyBalancesQuery + { + UserId = userId, + WeekDefinitionId = request.WeekDefinitionId, + OnlyActive = request.OnlyActive, + PaginationState = request.PaginationState + }; + + return await _mediator.Send(query, cancellationToken); + } +} diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs index 0512568..170a483 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs @@ -1,4 +1,5 @@ using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetAllClubMemberships; +using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembership; using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubStatistics; using CMSMicroservice.Protobuf.Protos.ClubMembership; using Google.Protobuf.WellKnownTypes; @@ -11,6 +12,37 @@ public class ClubMembershipProfile : IRegister { public void Register(TypeAdapterConfig config) { + // ===================== + // GetClubMembership + // ===================== + + // GetClubMembershipRequest -> GetClubMembershipQuery + config.NewConfig() + .MapWith(src => new GetClubMembershipQuery + { + UserId = src.UserId + }); + + // ClubMembershipDto -> GetClubMembershipResponse + config.NewConfig() + .MapWith(src => new GetClubMembershipResponse + { + Id = src.Id, + UserId = src.UserId, + PackageId = 0, // Not available + PackageName = string.Empty, // Not available + ActivationCode = string.Empty, // Not available + ActivatedAt = src.ActivatedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.ActivatedAt.Value, DateTimeKind.Utc)) + : null, + ExpiresAt = null, // Not available + IsActive = src.IsActive, + Created = Timestamp.FromDateTimeOffset(src.Created), + Features = { }, // Empty for now + Status = src.IsActive ? "Active" : "Inactive", + DaysRemaining = 0 // Calculate if ExpiresAt is available + }); + // ===================== // GetAllClubMemberships // ===================== diff --git a/src/CMSMicroservice.WebApi/Common/Mappings/CommissionProfile.cs b/src/CMSMicroservice.WebApi/Common/Mappings/CommissionProfile.cs index 001f3bd..c31a0db 100644 --- a/src/CMSMicroservice.WebApi/Common/Mappings/CommissionProfile.cs +++ b/src/CMSMicroservice.WebApi/Common/Mappings/CommissionProfile.cs @@ -1,4 +1,6 @@ +using System.Linq; using CMSMicroservice.Application.CommissionCQ.Queries.GetUserWeeklyBalances; +using CMSMicroservice.Application.CommissionCQ.Queries.GetMyWeeklyBalances; using CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks; using CMSMicroservice.Application.CommissionCQ.Queries.GetUserCommissionPayouts; using CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts; @@ -159,5 +161,44 @@ public class CommissionProfile : IRegister ? Timestamp.FromDateTime(src.CalculatedDate.Value.ToUniversalTime()) : null) .Map(dest => dest.DatePersian, src => src.DatePersian); + + // GetMyWeeklyBalances Request Mapping + config.NewConfig() + .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId != null ? src.WeekDefinitionId.Value : (long?)null) + .Map(dest => dest.OnlyActive, src => src.OnlyActive) + .Map(dest => dest.PaginationState, src => new PaginationState + { + PageNumber = src.PageNumber > 0 ? src.PageNumber : 1, + PageSize = src.PageSize > 0 ? src.PageSize : 10 + }); + + // GetMyWeeklyBalances Response Mapping + config.NewConfig() + .Map(dest => dest.MetaData, src => src.MetaData != null + ? new CustomerMetaData { TotalCount = src.MetaData.TotalCount } + : new CustomerMetaData()) + .Map(dest => dest.Balances, src => src.Models) + .Map(dest => dest.TotalLeftBalances, src => src.Models.Sum(m => m.LeftLegTotal)) + .Map(dest => dest.TotalRightBalances, src => src.Models.Sum(m => m.RightLegTotal)) + .Map(dest => dest.WeakerLeg, src => + src.Models.Sum(m => m.LeftLegTotal) < src.Models.Sum(m => m.RightLegTotal) + ? "Left" + : src.Models.Sum(m => m.LeftLegTotal) > src.Models.Sum(m => m.RightLegTotal) + ? "Right" + : "Equal"); + + // CustomerWeeklyBalanceModel Mapping + config.NewConfig() + .Map(dest => dest.Id, src => src.Id) + .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId) + .Map(dest => dest.WeekDisplayName, src => src.WeekDisplayName) + .Map(dest => dest.LeftLegBalances, src => src.LeftLegTotal) + .Map(dest => dest.RightLegBalances, src => src.RightLegTotal) + .Map(dest => dest.TotalBalances, src => src.TotalBalances) + .Map(dest => dest.WeeklyPoolContribution, src => src.WeeklyPoolContribution) + .Map(dest => dest.IsExpired, src => src.IsExpired) + .Map(dest => dest.CalculatedAt, src => src.CalculatedAt.HasValue + ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.CalculatedAt.Value, DateTimeKind.Utc)) + : null); } } diff --git a/src/CMSMicroservice.WebApi/Services/ClubMembershipService.cs b/src/CMSMicroservice.WebApi/Services/ClubMembershipService.cs index 0b8cfa5..94784e0 100644 --- a/src/CMSMicroservice.WebApi/Services/ClubMembershipService.cs +++ b/src/CMSMicroservice.WebApi/Services/ClubMembershipService.cs @@ -1,3 +1,4 @@ +using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Protobuf.Protos.ClubMembership; using CMSMicroservice.WebApi.Common.Services; using CMSMicroservice.Application.ClubMembershipCQ.Commands.ActivateClubMembership; @@ -10,16 +11,24 @@ using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubMembershipHist using CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubStatistics; using CMSMicroservice.Application.ClubFeatureCQ.Queries.GetUserClubFeatures; using CMSMicroservice.Application.ClubFeatureCQ.Commands.ToggleUserClubFeature; +using Microsoft.Extensions.Logging; namespace CMSMicroservice.WebApi.Services; public class ClubMembershipService : ClubMembershipContract.ClubMembershipContractBase { private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; + private readonly ICurrentUserService _currentUserService; + private readonly ILogger _logger; - public ClubMembershipService(IDispatchRequestToCQRS dispatchRequestToCQRS) + public ClubMembershipService( + IDispatchRequestToCQRS dispatchRequestToCQRS, + ICurrentUserService currentUserService, + ILogger logger) { _dispatchRequestToCQRS = dispatchRequestToCQRS; + _currentUserService = currentUserService; + _logger = logger; } public override async Task ActivateClubMembership(ActivateClubMembershipRequest request, ServerCallContext context) @@ -39,6 +48,25 @@ public class ClubMembershipService : ClubMembershipContract.ClubMembershipContra public override async Task GetClubMembership(GetClubMembershipRequest request, ServerCallContext context) { + // اگر UserId در request نیست یا صفر است، از JWT بخوان + if (request.UserId <= 0) + { + if (long.TryParse(_currentUserService.UserId, out var tokenUserId) && tokenUserId > 0) + { + _logger.LogInformation("GetClubMembership: Reading UserId from JWT token: {UserId}", tokenUserId); + request = new GetClubMembershipRequest { UserId = tokenUserId }; + } + else + { + _logger.LogWarning("GetClubMembership: No valid UserId in request or JWT token"); + throw new RpcException(new Status(StatusCode.Unauthenticated, "کاربر احراز هویت نشده است")); + } + } + else + { + _logger.LogInformation("GetClubMembership: Using UserId from request: {UserId}", request.UserId); + } + return await _dispatchRequestToCQRS.Handle(request, context); } diff --git a/src/CMSMicroservice.WebApi/Services/CommissionService.cs b/src/CMSMicroservice.WebApi/Services/CommissionService.cs index dd89ade..2b7990b 100644 --- a/src/CMSMicroservice.WebApi/Services/CommissionService.cs +++ b/src/CMSMicroservice.WebApi/Services/CommissionService.cs @@ -12,6 +12,7 @@ using CMSMicroservice.Application.CommissionCQ.Queries.GetWeeklyCommissionPool; using CMSMicroservice.Application.CommissionCQ.Queries.GetUserCommissionPayouts; using CMSMicroservice.Application.CommissionCQ.Queries.GetCommissionPayoutHistory; using CMSMicroservice.Application.CommissionCQ.Queries.GetUserWeeklyBalances; +using CMSMicroservice.Application.CommissionCQ.Queries.GetMyWeeklyBalances; using CMSMicroservice.Application.CommissionCQ.Queries.GetAllWeeklyPools; using CMSMicroservice.Application.CommissionCQ.Queries.GetWithdrawalRequests; using CMSMicroservice.Application.CommissionCQ.Queries.GetWorkerStatus; @@ -134,4 +135,9 @@ public class CommissionService : CommissionContract.CommissionContractBase { return await _dispatchRequestToCQRS.Handle(request, context); } + + public override async Task GetMyWeeklyBalances(GetMyWeeklyBalancesRequest request, ServerCallContext context) + { + return await _dispatchRequestToCQRS.Handle(request, context); + } } diff --git a/src/CMSMicroservice.WebApi/Services/ConfigurationService.cs b/src/CMSMicroservice.WebApi/Services/ConfigurationService.cs index fa0fda6..9618bb4 100644 --- a/src/CMSMicroservice.WebApi/Services/ConfigurationService.cs +++ b/src/CMSMicroservice.WebApi/Services/ConfigurationService.cs @@ -1,7 +1,10 @@ +using CMSMicroservice.Application.ClubFeatureCQ.Queries.GetUserClubFeatures; +using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Common; using CMSMicroservice.Protobuf.Protos.Configuration; using Google.Protobuf.WellKnownTypes; using Grpc.Core; +using MediatR; using Microsoft.Extensions.Logging; namespace CMSMicroservice.WebApi.Services; @@ -12,10 +15,17 @@ namespace CMSMicroservice.WebApi.Services; public class ConfigurationService : ConfigurationContract.ConfigurationContractBase { private readonly ILogger _logger; + private readonly ICurrentUserService _currentUserService; + private readonly IMediator _mediator; - public ConfigurationService(ILogger logger) + public ConfigurationService( + ILogger logger, + ICurrentUserService currentUserService, + IMediator mediator) { _logger = logger; + _currentUserService = currentUserService; + _mediator = mediator; } /// @@ -41,6 +51,61 @@ public class ConfigurationService : ConfigurationContract.ConfigurationContractB return Task.FromResult(response); } + /// + /// دریافت تنظیمات باشگاه مشتریان + /// + public override Task GetClubConfiguration(Empty request, ServerCallContext context) + { + var response = new GetClubConfigurationResponse + { + ActivationFee = SystemConstants.ClubActivationFee, + MembershipGiftValue = SystemConstants.ClubMembershipGiftValue + }; + + _logger.LogDebug("Club configuration requested: ActivationFee={ActivationFee}, GiftValue={GiftValue}", + response.ActivationFee, response.MembershipGiftValue); + + return Task.FromResult(response); + } + + /// + /// دریافت ویژگی‌های باشگاه مشتریان برای کاربر جاری + /// + public override async Task GetClubFeatures(Empty request, ServerCallContext context) + { + // دریافت UserId از JWT + if (!long.TryParse(_currentUserService.UserId, out var userId) || userId <= 0) + { + _logger.LogWarning("GetClubFeatures called without valid user authentication"); + return new GetClubFeaturesResponse(); // لیست خالی برای کاربران غیر احراز هویت شده + } + + // فراخوانی GetUserClubFeatures از طریق MediatR (CQRS داخلی) + var query = new GetUserClubFeaturesQuery { UserId = userId }; + var userFeatures = await _mediator.Send(query, context.CancellationToken); + + // تبدیل به فرمت GetClubFeaturesResponse + var response = new GetClubFeaturesResponse(); + foreach (var feature in userFeatures) + { + response.Features.Add(new ClubFeatureModel + { + Id = feature.ClubFeatureId, + Title = feature.FeatureTitle ?? string.Empty, + Description = feature.FeatureDescription ?? string.Empty, + IsEnabled = feature.IsActive, + DisplayOrder = feature.SortOrder, + GrantedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(feature.GrantedAt, DateTimeKind.Utc)), + CreatedAt = Timestamp.FromDateTime(DateTime.SpecifyKind(feature.CreatedAt, DateTimeKind.Utc)), + Notes = feature.Notes ?? string.Empty + }); + } + + _logger.LogDebug("Club features requested for user {UserId}: {Count} features returned", userId, response.Features.Count); + + return response; + } + /// /// دریافت تمام تنظیمات ///