From 2ca3fd29f9adfa9c7b953e5379922785b45fdacd Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Sun, 22 Feb 2026 23:51:39 +0330 Subject: [PATCH] =?UTF-8?q?feat:=20admin=20force=20activation=20=E2=80=94?= =?UTF-8?q?=20skip=20order/wallet=20checks=20for=20BackOffice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Proto: add force_activation field to ActivateClubMembershipRequest - Command: add ForceActivation property - Handler: wrap steps 2-5 in ForceActivation guard - Skip PackagePurchaseMethod check (set to DirectPurchase if None) - Skip wallet balance check - Skip Magic wallet mode check - Skip UserOrder/Transaction validation - Proto NuGet bumped to 0.0.184 --- .../ActivateClubMembershipCommand.cs | 5 + .../ActivateClubMembershipCommandHandler.cs | 187 ++++++++++-------- .../CMSMicroservice.Protobuf.csproj | 2 +- .../Protos/clubmembership.proto | 1 + 4 files changed, 110 insertions(+), 85 deletions(-) diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommand.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommand.cs index 6d94a03..2706c91 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommand.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommand.cs @@ -12,4 +12,9 @@ public record ActivateClubMembershipCommand : IRequest /// شناسه کاربر /// public long UserId { get; init; } + + /// + /// فعال‌سازی اجباری توسط ادمین — بدون بررسی سفارش و کیف‌پول + /// + public bool ForceActivation { get; init; } } diff --git a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs index 65b279d..20e1def 100644 --- a/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs +++ b/src/CMSMicroservice.Application/ClubMembershipCQ/Commands/ActivateClubMembership/ActivateClubMembershipCommandHandler.cs @@ -54,94 +54,113 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler w.UserId == user.Id, cancellationToken); + + if (wallet == null) + { + _logger.LogError("Wallet not found for UserId: {UserId}", request.UserId); + throw new NotFoundException("کیف پول کاربر یافت نشد"); + } + + if (wallet.Balance < SystemConstants.BasePackageAmount) + { + _logger.LogWarning( + "User {UserId} has insufficient balance: {Balance}", + request.UserId, + wallet.Balance + ); + throw new BadRequestException( + $"برای فعالسازی باشگاه مشتریان باید حداقل {SystemConstants.BasePackageAmount:N0} ریال موجودی اصلی داشته باشید" + ); + } + + // 3.5. بررسی وضعیت کیف‌پول جادویی — اگر در حالت Magic است، فعالسازی مجاز نیست + if (wallet.WalletMode == WalletMode.Magic) + { + _logger.LogWarning( + "User {UserId} cannot activate club while in Magic wallet mode", + request.UserId + ); + throw new BadRequestException( + "ابتدا باید چرخه کیف‌پول جادویی تکمیل شود" + ); + } + + // 4. پیدا کردن UserOrder با PackageId + var packageOrder = await _context.UserOrders + .Include(o => o.Transaction) + .Where(o => + o.UserId == user.Id && + o.PackageId != null && + o.PaymentStatus == PaymentStatus.Success) + .OrderByDescending(o => o.Created) + .FirstOrDefaultAsync(cancellationToken); + + if (packageOrder == null) + { + _logger.LogWarning( + "No successful package order found for UserId: {UserId}", + request.UserId + ); + throw new NotFoundException("سفارش پکیج طلایی یافت نشد"); + } + + // 5. بررسی Transaction + if (packageOrder.Transaction == null) + { + _logger.LogError( + "Transaction not found for OrderId: {OrderId}", + packageOrder.Id + ); + throw new NotFoundException("تراکنش مربوط به سفارش یافت نشد"); + } + + var transaction = packageOrder.Transaction; + + if (transaction.Type != TransactionType.DepositIpg && + transaction.Type != TransactionType.DepositExternal1) + { + _logger.LogWarning( + "Invalid transaction type for OrderId {OrderId}: {Type}", + packageOrder.Id, + transaction.Type + ); + throw new BadRequestException( + "تراکنش معتبر برای فعالسازی باشگاه یافت نشد" + ); + } + } + else + { + _logger.LogInformation( + "Force activation by admin for UserId: {UserId} — skipping order/wallet validation", request.UserId ); - throw new BadRequestException( - "برای فعالسازی باشگاه مشتریان ابتدا باید پکیج طلایی خریداری کنید" - ); - } - // 3. بررسی موجودی کیف پول - var wallet = await _context.UserWallets - .FirstOrDefaultAsync(w => w.UserId == user.Id, cancellationToken); - - if (wallet == null) - { - _logger.LogError("Wallet not found for UserId: {UserId}", request.UserId); - throw new NotFoundException("کیف پول کاربر یافت نشد"); - } - - if (wallet.Balance < SystemConstants.BasePackageAmount) - { - _logger.LogWarning( - "User {UserId} has insufficient balance: {Balance}", - request.UserId, - wallet.Balance - ); - throw new BadRequestException( - $"برای فعالسازی باشگاه مشتریان باید حداقل {SystemConstants.BasePackageAmount:N0} ریال موجودی اصلی داشته باشید" - ); - } - - // 3.5. بررسی وضعیت کیف‌پول جادویی — اگر در حالت Magic است، فعالسازی مجاز نیست - if (wallet.WalletMode == WalletMode.Magic) - { - _logger.LogWarning( - "User {UserId} cannot activate club while in Magic wallet mode", - request.UserId - ); - throw new BadRequestException( - "ابتدا باید چرخه کیف‌پول جادویی تکمیل شود" - ); - } - - // 4. پیدا کردن UserOrder با PackageId - var packageOrder = await _context.UserOrders - .Include(o => o.Transaction) - .Where(o => - o.UserId == user.Id && - o.PackageId != null && - o.PaymentStatus == PaymentStatus.Success) - .OrderByDescending(o => o.Created) - .FirstOrDefaultAsync(cancellationToken); - - if (packageOrder == null) - { - _logger.LogWarning( - "No successful package order found for UserId: {UserId}", - request.UserId - ); - throw new NotFoundException("سفارش پکیج طلایی یافت نشد"); - } - - // 5. بررسی Transaction - if (packageOrder.Transaction == null) - { - _logger.LogError( - "Transaction not found for OrderId: {OrderId}", - packageOrder.Id - ); - throw new NotFoundException("تراکنش مربوط به سفارش یافت نشد"); - } - - var transaction = packageOrder.Transaction; - - if (transaction.Type != TransactionType.DepositIpg && - transaction.Type != TransactionType.DepositExternal1) - { - _logger.LogWarning( - "Invalid transaction type for OrderId {OrderId}: {Type}", - packageOrder.Id, - transaction.Type - ); - throw new BadRequestException( - "تراکنش معتبر برای فعالسازی باشگاه یافت نشد" - ); + // در فعال‌سازی اجباری، اگر PackagePurchaseMethod تنظیم نشده، مقدار DirectPurchase بگذار + if (user.PackagePurchaseMethod == PackagePurchaseMethod.None) + { + user.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase; + _context.Users.Update(user); + await _context.SaveChangesAsync(cancellationToken); + } } // 6. بررسی عضویت فعلی diff --git a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj index a06c1ac..c07bc07 100644 --- a/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj +++ b/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj @@ -3,7 +3,7 @@ net9.0 enable enable - 0.0.183 + 0.0.184 None False False diff --git a/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto b/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto index 9951376..9520d8d 100644 --- a/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto +++ b/src/CMSMicroservice.Protobuf/Protos/clubmembership.proto @@ -80,6 +80,7 @@ message ActivateClubMembershipRequest int64 package_id = 2; google.protobuf.StringValue activation_code = 3; int32 duration_months = 4; + bool force_activation = 5; } // Deactivate Command