1e7c17f090
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 8m22s
- Refactor ActivateClubMembershipCommandHandler to use UserPackagePurchases instead of UserOrders for package activation. - Modify PlaceOrderCommandHandler to redirect payment callbacks to the front office. - Update ChargeDiscountWalletCommandHandler and ChargeMagicWalletCommandHandler to direct payment callbacks to the front office. - Remove PaymentCallbackController and integrate payment verification directly into DiscountOrderService and UserWalletService. - Add CustomerVerifyDiscountOrderPayment RPC to DiscountOrderService for verifying discount order payments. - Implement VerifyMagicCharge and VerifyDiscountCharge methods in UserWalletService for wallet charge verifications. - Update appsettings.json to use local URLs for development. - Remove appsettings.Development.json as it is no longer needed. - Comment out history tracking methods in ClubMembershipCycle and Package classes. - Update PackageService to automatically activate club membership after successful payment verification. - Adjust UserService to generate JWT tokens with user details.
184 lines
7.3 KiB
C#
184 lines
7.3 KiB
C#
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.Configuration;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeMagicWallet;
|
|
|
|
public class ChargeMagicWalletCommandHandler
|
|
: IRequestHandler<ChargeMagicWalletCommand, PaymentInitiateResult>
|
|
{
|
|
private readonly IApplicationDbContext _context;
|
|
private readonly IPaymentGatewayService _paymentGateway;
|
|
private readonly IConfiguration _configuration;
|
|
private readonly ILogger<ChargeMagicWalletCommandHandler> _logger;
|
|
|
|
public ChargeMagicWalletCommandHandler(
|
|
IApplicationDbContext context,
|
|
IPaymentGatewayService paymentGateway,
|
|
IConfiguration configuration,
|
|
ILogger<ChargeMagicWalletCommandHandler> logger)
|
|
{
|
|
_context = context;
|
|
_paymentGateway = paymentGateway;
|
|
_configuration = configuration;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<PaymentInitiateResult> Handle(
|
|
ChargeMagicWalletCommand request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
try
|
|
{
|
|
_logger.LogInformation(
|
|
"Initiating magic wallet charge for UserId: {UserId}, Amount: {Amount}",
|
|
request.UserId,
|
|
request.Amount
|
|
);
|
|
|
|
// 1. بررسی وجود کاربر
|
|
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);
|
|
}
|
|
|
|
// 2. بررسی وجود کیفپول
|
|
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("کیف پول کاربر یافت نشد");
|
|
}
|
|
|
|
// 3. بررسی حالت جادویی
|
|
if (wallet.WalletMode != WalletMode.Magic)
|
|
{
|
|
_logger.LogWarning(
|
|
"User {UserId} wallet is not in Magic mode (current: {Mode})",
|
|
request.UserId,
|
|
wallet.WalletMode
|
|
);
|
|
throw new BadRequestException(
|
|
"شارژ جادویی فقط در حالت کیفپول جادویی امکانپذیر است"
|
|
);
|
|
}
|
|
|
|
// 3.5. بارگذاری پکیج کاربر برای سقف کیفپول جادویی
|
|
var currentCycle = await _context.ClubMembershipCycles
|
|
.FirstOrDefaultAsync(c => c.UserId == request.UserId && c.IsCurrentCycle, cancellationToken);
|
|
var package = currentCycle != null
|
|
? await _context.Packages.FirstOrDefaultAsync(p => p.Id == currentCycle.PackageId, cancellationToken)
|
|
: await _context.Packages.FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken);
|
|
if (package == null)
|
|
throw new NotFoundException("پکیج یافت نشد");
|
|
|
|
// 4. بررسی سقف واریزی (per-cycle)
|
|
var remainingDeposit = package.MagicWalletMaxDeposit - wallet.MagicTotalDeposited;
|
|
|
|
if (remainingDeposit <= 0)
|
|
{
|
|
_logger.LogWarning(
|
|
"User {UserId} has reached magic deposit cap. TotalDeposited: {TotalDeposited}",
|
|
request.UserId,
|
|
wallet.MagicTotalDeposited
|
|
);
|
|
throw new BadRequestException(
|
|
"سقف شارژ جادویی در این دور پر شده است"
|
|
);
|
|
}
|
|
|
|
if (request.Amount > remainingDeposit)
|
|
{
|
|
_logger.LogWarning(
|
|
"User {UserId} amount {Amount} exceeds remaining deposit cap {Remaining}",
|
|
request.UserId,
|
|
request.Amount,
|
|
remainingDeposit
|
|
);
|
|
throw new BadRequestException(
|
|
$"مبلغ واریزی بیش از سقف باقیمانده است. حداکثر مبلغ قابل واریز: {remainingDeposit:N0} تومان"
|
|
);
|
|
}
|
|
|
|
// 5. ایجاد درخواست پرداخت — callback مستقیم به فرانتآفیس
|
|
var frontOfficeBaseUrl = _configuration["FrontOfficeBaseUrl"] ?? "https://localhost:5268";
|
|
var callbackUrl = $"{frontOfficeBaseUrl}/profile/payment-callback?type=magic-wallet";
|
|
|
|
var paymentRequest = new PaymentRequest
|
|
{
|
|
Amount = request.Amount,
|
|
UserId = user.Id,
|
|
Mobile = user.Mobile ?? "",
|
|
CallbackUrl = callbackUrl,
|
|
Description = $"شارژ کیفپول جادویی - کاربر {user.Id}"
|
|
};
|
|
|
|
var paymentResult = await _paymentGateway.InitiatePaymentAsync(paymentRequest);
|
|
|
|
if (!paymentResult.IsSuccess)
|
|
{
|
|
_logger.LogError(
|
|
"Payment gateway failed for magic charge UserId {UserId}: {ErrorMessage}",
|
|
user.Id,
|
|
paymentResult.ErrorMessage
|
|
);
|
|
|
|
throw new Exception($"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}");
|
|
}
|
|
|
|
// 6. ثبت PaymentTransaction
|
|
var paymentTx = new PaymentTransaction
|
|
{
|
|
GatewayProvider = _configuration["PaymentProvider"] ?? "zarinpal",
|
|
MerchantId = _configuration["ZarinPal:MerchantId"] ?? "",
|
|
Amount = request.Amount,
|
|
CallbackUrl = callbackUrl,
|
|
Description = $"شارژ کیفپول جادویی - کاربر {user.Id}",
|
|
Mobile = user.Mobile,
|
|
UserId = user.Id,
|
|
RequestStatusCode = 100,
|
|
RequestStatusMessage = "Success",
|
|
Authority = paymentResult.RefId,
|
|
PaymentStatus = false
|
|
};
|
|
|
|
_context.PaymentTransactions.Add(paymentTx);
|
|
await _context.SaveChangesAsync(cancellationToken);
|
|
|
|
_logger.LogInformation(
|
|
"Magic wallet charge initiated. UserId: {UserId}, Amount: {Amount}, " +
|
|
"RemainingCap: {Remaining}, RefId: {RefId}, PaymentTxId: {PaymentTxId}",
|
|
user.Id,
|
|
request.Amount,
|
|
remainingDeposit - request.Amount,
|
|
paymentResult.RefId,
|
|
paymentTx.Id
|
|
);
|
|
|
|
return paymentResult;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(
|
|
ex,
|
|
"Error in ChargeMagicWalletCommand for UserId: {UserId}",
|
|
request.UserId
|
|
);
|
|
throw;
|
|
}
|
|
}
|
|
}
|