diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/AcceptClubMembershipContract/AcceptClubMembershipContractCommandHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/AcceptClubMembershipContract/AcceptClubMembershipContractCommandHandler.cs index 16f0f1e..9004fcb 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/AcceptClubMembershipContract/AcceptClubMembershipContractCommandHandler.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/AcceptClubMembershipContract/AcceptClubMembershipContractCommandHandler.cs @@ -1,5 +1,9 @@ using CMSMicroservice.Application.Common.Exceptions; +using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Entities; +using CMSMicroservice.Domain.Entities.Club; +using CMSMicroservice.Domain.Entities.Commission; +using CMSMicroservice.Domain.Entities.History; using CMSMicroservice.Domain.Enums; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -12,6 +16,8 @@ namespace CMSMicroservice.Application.ClubMembershipCQ.Commands.AcceptClubMember /// 1. کد OTP را تایید می‌کند /// 2. قرارداد را در جدول UserContract ثبت می‌کند /// 3. باشگاه مشتری را فعال می‌کند (IsActive = true) +/// 4. مبلغ را به Pool هفته جاری اضافه می‌کند +/// 5. ویژگی‌های باشگاه را به کاربر اعطا می‌کند /// public class AcceptClubMembershipContractCommandHandler : IRequestHandler @@ -19,6 +25,8 @@ public class AcceptClubMembershipContractCommandHandler private readonly IApplicationDbContext _context; private readonly IConfiguration _cfg; private readonly IHashService _hashService; + private readonly ICurrentUserService _currentUser; + private readonly IWeekDefinitionRepository _weekRepository; private readonly ILogger _logger; private const int MaxAttempts = 5; @@ -28,11 +36,15 @@ public class AcceptClubMembershipContractCommandHandler IApplicationDbContext context, IConfiguration cfg, IHashService hashService, + ICurrentUserService currentUser, + IWeekDefinitionRepository weekRepository, ILogger logger) { _context = context; _cfg = cfg; _hashService = hashService; + _currentUser = currentUser; + _weekRepository = weekRepository; _logger = logger; } @@ -114,33 +126,173 @@ public class AcceptClubMembershipContractCommandHandler }; await _context.UserContracts.AddAsync(userContract, cancellationToken); - // 6. فعال‌سازی باشگاه مشتریان - if (user.ClubMembership == null) + // 6. دریافت مقادیر از تنظیمات سیستم + var giftValueConfig = await _context.SystemConfigurations + .FirstOrDefaultAsync( + c => c.Key == "Club.MembershipGiftValue" && c.IsActive, + cancellationToken + ); + + var activationFeeConfig = await _context.SystemConfigurations + .FirstOrDefaultAsync( + c => c.Key == "Club.ActivationFee" && c.IsActive, + cancellationToken + ); + + long giftValue = 28_000_000; // مقدار پیش‌فرض + if (giftValueConfig != null && long.TryParse(giftValueConfig.Value, out var configValue)) { - user.ClubMembership = new Domain.Entities.Club.ClubMembership + giftValue = configValue; + _logger.LogInformation( + "Using Club.MembershipGiftValue from configuration: {GiftValue}", + giftValue + ); + } + + long activationFeeValue = 25_200_000; // مقدار پیش‌فرض + if (activationFeeConfig != null && long.TryParse(activationFeeConfig.Value, out var activationFeeConfigValue)) + { + activationFeeValue = activationFeeConfigValue; + _logger.LogInformation( + "Using Club.ActivationFee from configuration: {activationFeeValue}", + activationFeeValue + ); + } + + // 7. فعال‌سازی باشگاه مشتریان + ClubMembership clubMembership; + bool isNewMembership = user.ClubMembership == null; + var activationDate = DateTime.Now; + + if (isNewMembership) + { + clubMembership = new ClubMembership { UserId = user.Id, IsActive = true, - ActivatedAt = DateTime.Now, - InitialContribution = 56_000_000, - GiftValue = 25_200_000, + ActivatedAt = activationDate, + InitialContribution = activationFeeValue, + GiftValue = giftValue, + TotalEarned = 0, PurchaseMethod = user.PackagePurchaseMethod }; - await _context.ClubMemberships.AddAsync(user.ClubMembership, cancellationToken); + await _context.ClubMemberships.AddAsync(clubMembership, cancellationToken); + + _logger.LogInformation( + "Created new club membership for UserId {UserId} via {Method}, GiftValue: {GiftValue}", + user.Id, + user.PackagePurchaseMethod, + giftValue + ); } else { - user.ClubMembership.IsActive = true; - user.ClubMembership.ActivatedAt = DateTime.Now; - _context.ClubMemberships.Update(user.ClubMembership); + clubMembership = user.ClubMembership!; + clubMembership.IsActive = true; + clubMembership.ActivatedAt = activationDate; + clubMembership.PurchaseMethod = user.PackagePurchaseMethod; + _context.ClubMemberships.Update(clubMembership); + + _logger.LogInformation( + "Reactivated club membership for UserId {UserId}", + user.Id + ); } await _context.SaveChangesAsync(cancellationToken); + // 8. ثبت تاریخچه + var history = new ClubMembershipHistory + { + ClubMembershipId = clubMembership.Id, + UserId = clubMembership.UserId, + OldIsActive = !isNewMembership && !user.ClubMembership!.IsActive, + NewIsActive = true, + Action = ClubMembershipAction.Activated, + Reason = isNewMembership + ? $"Initial activation via contract signing - {user.PackagePurchaseMethod}" + : $"Reactivated via contract signing - {user.PackagePurchaseMethod}", + PerformedBy = _currentUser.GetPerformedBy() + }; + + _context.ClubMembershipHistories.Add(history); + await _context.SaveChangesAsync(cancellationToken); + + // 9. اضافه کردن مبلغ به Pool هفته جاری + var currentWeekDefinitionId = GetCurrentWeekDefinitionId(); + var weeklyPool = await _context.WeeklyCommissionPools + .FirstOrDefaultAsync(p => p.WeekDefinitionId == currentWeekDefinitionId, cancellationToken); + + if (weeklyPool == null) + { + weeklyPool = new WeeklyCommissionPool + { + WeekDefinitionId = currentWeekDefinitionId, + TotalPoolAmount = activationFeeValue, + TotalBalances = 0, + ValuePerBalance = 0, + IsCalculated = false, + CalculatedAt = null + }; + + await _context.WeeklyCommissionPools.AddAsync(weeklyPool, cancellationToken); + + _logger.LogInformation( + "Created new WeeklyCommissionPool for WeekDefinitionId={WeekDefinitionId} with initial amount: {Amount}", + currentWeekDefinitionId, + activationFeeValue + ); + } + else + { + weeklyPool.TotalPoolAmount += activationFeeValue; + _context.WeeklyCommissionPools.Update(weeklyPool); + + _logger.LogInformation( + "Added {Amount} to existing WeeklyCommissionPool for WeekDefinitionId={WeekDefinitionId}. New total: {NewTotal}", + activationFeeValue, + currentWeekDefinitionId, + weeklyPool.TotalPoolAmount + ); + } + + await _context.SaveChangesAsync(cancellationToken); + + // 10. اعطای ویژگی‌های باشگاه برای کاربر (فقط برای عضویت جدید) + if (isNewMembership) + { + var clubFeatures = await _context.ClubFeatures + .Where(f => !f.IsDeleted && new long[] { 1, 2, 3, 4 }.Contains(f.Id)) + .ToListAsync(cancellationToken); + + if (clubFeatures.Any()) + { + var userClubFeatures = clubFeatures.Select(feature => new UserClubFeature + { + UserId = user.Id, + ClubMembershipId = clubMembership.Id, + ClubFeatureId = feature.Id, + GrantedAt = activationDate, + IsActive = true, + Notes = "اعطا شده هنگام امضای قرارداد" + }).ToList(); + + _context.UserClubFeatures.AddRange(userClubFeatures); + await _context.SaveChangesAsync(cancellationToken); + + _logger.LogInformation( + "Granted {Count} club features to UserId {UserId}", + clubFeatures.Count, + user.Id + ); + } + } + _logger.LogInformation( - "Club membership contract accepted and activated for UserId: {UserId}, ContractId: {ContractId}", + "Club membership contract accepted and activated for UserId: {UserId}, ContractId: {ContractId}, MembershipId: {MembershipId}", request.UserId, - userContract.Id + userContract.Id, + clubMembership.Id ); return new AcceptClubMembershipContractResponseDto @@ -151,6 +303,19 @@ public class AcceptClubMembershipContractCommandHandler }; } + /// + /// دریافت شناسه تعریف هفته جاری + /// + private long GetCurrentWeekDefinitionId() + { + var week = _weekRepository.GetCurrentWeek(); + if (week == null) + { + throw new InvalidOperationException("هفته جاری در سیستم تعریف نشده است"); + } + return week.Id; + } + private async Task<(bool Success, string Message)> VerifyOtpAsync( string mobile, string code,