Files
CMS/src/CMSMicroservice.Application/ManualPaymentCQ/Commands/CreateManualPayment/CreateManualPaymentCommandHandler.cs
T
masoodafar-web 427d2cce1d
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 6m45s
feat(package): update package purchase methods and enhance Protobuf definitions
- Changed package purchase method from DirectPurchase to Manual in multiple command handlers to reflect new business logic.
- Added Manual purchase method to PackagePurchaseMethod enum for clarity.
- Introduced new RPC method GetCustomerPackagePurchaseRollup in Protobuf for summarizing customer package purchases.
- Updated UserPackagePurchaseProfile and UserPackagePurchaseService to support new rollup functionality.
- Bumped Protobuf project version to accommodate new features.
2026-08-08 21:59:14 +03:30

218 lines
8.8 KiB
C#

using CMSMicroservice.Application.ClubMembershipCQ.Commands.ActivateClubMembership;
using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Common;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Entities.Payment;
using CMSMicroservice.Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace CMSMicroservice.Application.ManualPaymentCQ.Commands.CreateManualPayment;
public class CreateManualPaymentCommandHandler : IRequestHandler<CreateManualPaymentCommand, long>
{
private readonly IApplicationDbContext _context;
private readonly ICurrentUserService _currentUser;
private readonly ISender _sender;
private readonly ILogger<CreateManualPaymentCommandHandler> _logger;
public CreateManualPaymentCommandHandler(
IApplicationDbContext context,
ICurrentUserService currentUser,
ISender sender,
ILogger<CreateManualPaymentCommandHandler> logger)
{
_context = context;
_currentUser = currentUser;
_sender = sender;
_logger = logger;
}
public async Task<long> Handle(
CreateManualPaymentCommand request,
CancellationToken cancellationToken)
{
try
{
_logger.LogInformation(
"Creating manual membership payment for UserId: {UserId}, Type: {Type}",
request.UserId,
request.Type
);
// 1. بررسی Admin فعلی
var currentUserId = _currentUser.UserId;
if (string.IsNullOrEmpty(currentUserId))
{
throw new UnauthorizedAccessException("کاربر احراز هویت نشده است");
}
if (!long.TryParse(currentUserId, out var adminUserId))
{
throw new UnauthorizedAccessException("شناسه کاربر نامعتبر است");
}
// 2. بررسی وجود کاربر
var user = await _context.Users
.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken);
if (user == null)
{
_logger.LogWarning("User not found: {UserId}", request.UserId);
throw new NotFoundException(nameof(User), request.UserId);
}
// 3. پیدا کردن کیف پول
var wallet = await _context.UserWallets
.FirstOrDefaultAsync(w => w.UserId == request.UserId, cancellationToken);
if (wallet == null)
{
_logger.LogError("Wallet not found for UserId: {UserId}", request.UserId);
throw new NotFoundException($"کیف پول کاربر {request.UserId} یافت نشد");
}
// 4. بارگذاری پکیج انتخاب‌شده (یا پکیج پایه اگر PackageId=0)
Domain.Entities.Package package;
if (request.PackageId > 0)
{
package = await _context.Packages
.FirstOrDefaultAsync(p => p.Id == request.PackageId && !p.IsDeleted, cancellationToken)
?? throw new NotFoundException($"پکیج با شناسه {request.PackageId} یافت نشد");
}
else
{
package = await _context.Packages
.FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken)
?? throw new NotFoundException("پکیج پایه یافت نشد");
}
var balanceAmount = package.Price;
var discountBalanceAmount = (long)(package.Price * package.DiscountMultiplier);
// 5. ثبت تراکنش
var transaction = new Transaction
{
Amount = balanceAmount,
Description = $"عضویت دستی باشگاه مشتریان - {request.Description} - مرجع: {request.ReferenceNumber}",
PaymentStatus = PaymentStatus.Success,
PaymentDate = DateTime.Now,
RefId = request.ReferenceNumber,
Type = TransactionType.DepositExternal1
};
_context.Transactions.Add(transaction);
await _context.SaveChangesAsync(cancellationToken);
// 6. ایجاد ManualPayment با وضعیت Approved (بدون نیاز به تایید دو مرحله‌ای)
var manualPayment = new ManualPayment
{
UserId = request.UserId,
Amount = balanceAmount,
Type = request.Type,
Description = request.Description,
ReferenceNumber = request.ReferenceNumber,
ImagePath = request.ImagePath,
ImageDocumentId = request.ImageDocumentId,
Status = ManualPaymentStatus.Approved,
RequestedBy = adminUserId,
ApprovedBy = adminUserId,
ApprovedAt = DateTime.Now,
TransactionId = transaction.Id
};
_context.ManualPayments.Add(manualPayment);
// 7. اعمال تغییرات بر کیف پول
var oldBalance = wallet.Balance;
var oldDiscountBalance = wallet.DiscountBalance;
wallet.Balance += balanceAmount;
wallet.DiscountBalance += discountBalanceAmount;
// 8. ثبت لاگ کیف پول
var walletLog = new UserWalletHistory
{
WalletId = wallet.Id,
CurrentBalance = 0,
ChangeValue = balanceAmount,
CurrentNetworkBalance = wallet.NetworkBalance,
ChangeNerworkValue = 0,
CurrentDiscountBalance =0,
ChangeDiscountValue = discountBalanceAmount,
IsIncrease = true,
RefrenceId = transaction.Id,
PackageId = package.Id
};
await _context.UserWalletHistories.AddAsync(walletLog, cancellationToken);
// 9. تنظیم روش خرید پکیج + ثبت ledger خرید دستی
user.PackagePurchaseMethod = PackagePurchaseMethod.Manual;
_context.UserPackagePurchases.Add(new UserPackagePurchase
{
UserId = request.UserId,
PackageId = package.Id,
PurchaseMethod = PackagePurchaseMethod.Manual,
PurchasedAt = DateTime.Now,
Amount = balanceAmount,
TransactionId = transaction.Id
});
// 10. ذخیره همه تغییرات
await _context.SaveChangesAsync(cancellationToken);
// 11. فعال‌سازی باشگاه مشتریان — ساخت Cycle و آماده‌سازی برای AcceptContract
// این مرحله تضمین می‌کند که:
// الف) ClubMembershipCycle ساخته شود تا والدین امتیاز «عضو جدید» بگیرند
// ب) Pool توسط AcceptContract (که کاربر در FO امضا می‌کند) شارژ شود
try
{
await _sender.Send(new ActivateClubMembershipCommand
{
UserId = request.UserId,
ForceActivation = true,
PackageId = package.Id
}, cancellationToken);
}
catch (Exception activateEx)
{
// عضویت باشگاه اختیاری است — خطا نباید پرداخت دستی را برگرداند
_logger.LogWarning(
activateEx,
"Club membership activation failed after manual payment for UserId {UserId} — payment recorded successfully",
request.UserId
);
}
_logger.LogInformation(
"Manual membership payment created successfully. " +
"ManualPaymentId: {Id}, UserId: {UserId}, TransactionId: {TransactionId}, " +
"Balance: {OldBalance} -> {NewBalance}, DiscountBalance: {OldDiscount} -> {NewDiscount}",
manualPayment.Id,
request.UserId,
transaction.Id,
oldBalance,
wallet.Balance,
oldDiscountBalance,
wallet.DiscountBalance
);
return manualPayment.Id;
}
catch (Exception ex) when (ex is not NotFoundException && ex is not UnauthorizedAccessException)
{
_logger.LogError(
ex,
"Error creating manual membership payment for UserId: {UserId}",
request.UserId
);
throw;
}
}
}