feat(wallet): add credit wallet functionality and update Protobuf definitions
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 9m49s
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 9m49s
- Introduced new CreditWalletCharge enum value to TransactionType for clarity. - Implemented InitiateCreditCharge and VerifyCreditCharge methods in UserWalletService for handling credit wallet transactions. - Updated ZarinpalReconciliationJob to support credit wallet payment verification. - Enhanced Protobuf definitions with new messages and RPC methods for credit wallet operations. - Bumped Protobuf project version to reflect the addition of new features.
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
|||||||
|
using CMSMicroservice.Application.Common.Models;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دستور شارژ کیف پول اصلی از طریق درگاه
|
||||||
|
/// </summary>
|
||||||
|
public class ChargeCreditWalletCommand : IRequest<PaymentInitiateResult>
|
||||||
|
{
|
||||||
|
public long UserId { get; set; }
|
||||||
|
public long Amount { get; set; }
|
||||||
|
}
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
using CMSMicroservice.Application.Common;
|
||||||
|
using CMSMicroservice.Application.Common.Exceptions;
|
||||||
|
using CMSMicroservice.Application.Common.Interfaces;
|
||||||
|
using CMSMicroservice.Application.Common.Models;
|
||||||
|
using CMSMicroservice.Domain.Entities;
|
||||||
|
using CMSMicroservice.Domain.Entities.Payment;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet;
|
||||||
|
|
||||||
|
public class ChargeCreditWalletCommandHandler
|
||||||
|
: IRequestHandler<ChargeCreditWalletCommand, PaymentInitiateResult>
|
||||||
|
{
|
||||||
|
private readonly IApplicationDbContext _context;
|
||||||
|
private readonly IPaymentGatewayService _paymentGateway;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly ILogger<ChargeCreditWalletCommandHandler> _logger;
|
||||||
|
private readonly IUserPaymentLock _paymentLock;
|
||||||
|
|
||||||
|
public ChargeCreditWalletCommandHandler(
|
||||||
|
IApplicationDbContext context,
|
||||||
|
IPaymentGatewayService paymentGateway,
|
||||||
|
IConfiguration configuration,
|
||||||
|
ILogger<ChargeCreditWalletCommandHandler> logger,
|
||||||
|
IUserPaymentLock paymentLock)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_paymentGateway = paymentGateway;
|
||||||
|
_configuration = configuration;
|
||||||
|
_logger = logger;
|
||||||
|
_paymentLock = paymentLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PaymentInitiateResult> Handle(
|
||||||
|
ChargeCreditWalletCommand request,
|
||||||
|
CancellationToken cancellationToken) =>
|
||||||
|
_paymentLock.ExecuteAsync(
|
||||||
|
PaymentLockScopes.Initiate(request.UserId),
|
||||||
|
PaymentLockStrategy.FailFast,
|
||||||
|
ct => HandleCore(request, ct),
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
private async Task<PaymentInitiateResult> HandleCore(
|
||||||
|
ChargeCreditWalletCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Charging credit wallet for UserId: {UserId}, Amount: {Amount}",
|
||||||
|
request.UserId,
|
||||||
|
request.Amount);
|
||||||
|
|
||||||
|
var user = await _context.Users
|
||||||
|
.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken)
|
||||||
|
?? throw new NotFoundException(nameof(User), request.UserId);
|
||||||
|
|
||||||
|
var wallet = await _context.UserWallets
|
||||||
|
.FirstOrDefaultAsync(w => w.UserId == request.UserId, cancellationToken)
|
||||||
|
?? throw new NotFoundException("کیف پول کاربر یافت نشد");
|
||||||
|
|
||||||
|
var frontOfficeBaseUrl = _configuration["FrontOfficeBaseUrl"] ?? "https://localhost:5268";
|
||||||
|
var callbackUrl = $"{frontOfficeBaseUrl}/profile/payment-callback?type=credit-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 UserId {UserId}: {ErrorMessage}",
|
||||||
|
user.Id,
|
||||||
|
paymentResult.ErrorMessage);
|
||||||
|
|
||||||
|
throw new Exception($"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}");
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
"Credit wallet charge initiated. UserId: {UserId}, RefId: {RefId}, PaymentTxId: {PaymentTxId}",
|
||||||
|
user.Id,
|
||||||
|
paymentResult.RefId,
|
||||||
|
paymentTx.Id);
|
||||||
|
|
||||||
|
return paymentResult;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
ex,
|
||||||
|
"Error in ChargeCreditWalletCommand for UserId: {UserId}",
|
||||||
|
request.UserId);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
using CMSMicroservice.Domain.Common;
|
||||||
|
using FluentValidation;
|
||||||
|
|
||||||
|
namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet;
|
||||||
|
|
||||||
|
public class ChargeCreditWalletCommandValidator : AbstractValidator<ChargeCreditWalletCommand>
|
||||||
|
{
|
||||||
|
public ChargeCreditWalletCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.UserId)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.WithMessage("شناسه کاربر باید بزرگتر از صفر باشد");
|
||||||
|
|
||||||
|
RuleFor(x => x.Amount)
|
||||||
|
.GreaterThanOrEqualTo(SystemConstants.DiscountWalletMinCharge)
|
||||||
|
.WithMessage("حداقل مبلغ شارژ ۱۰,۰۰۰ تومان است")
|
||||||
|
.LessThanOrEqualTo(SystemConstants.WalletMaxSafeAmount)
|
||||||
|
.WithMessage("مبلغ وارد شده بیش از حد مجاز است");
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// دستور تأیید شارژ کیف پول اصلی
|
||||||
|
/// </summary>
|
||||||
|
public class VerifyCreditWalletChargeCommand : IRequest<bool>
|
||||||
|
{
|
||||||
|
public long UserId { get; set; }
|
||||||
|
public long Amount { get; set; }
|
||||||
|
public string Authority { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
+157
@@ -0,0 +1,157 @@
|
|||||||
|
using CMSMicroservice.Application.Common;
|
||||||
|
using CMSMicroservice.Application.Common.Exceptions;
|
||||||
|
using CMSMicroservice.Application.Common.Interfaces;
|
||||||
|
using CMSMicroservice.Domain.Entities;
|
||||||
|
using CMSMicroservice.Domain.Enums;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge;
|
||||||
|
|
||||||
|
public class VerifyCreditWalletChargeCommandHandler
|
||||||
|
: IRequestHandler<VerifyCreditWalletChargeCommand, bool>
|
||||||
|
{
|
||||||
|
private readonly IApplicationDbContext _context;
|
||||||
|
private readonly IPaymentGatewayService _paymentGateway;
|
||||||
|
private readonly ILogger<VerifyCreditWalletChargeCommandHandler> _logger;
|
||||||
|
private readonly IUserPaymentLock _paymentLock;
|
||||||
|
|
||||||
|
public VerifyCreditWalletChargeCommandHandler(
|
||||||
|
IApplicationDbContext context,
|
||||||
|
IPaymentGatewayService paymentGateway,
|
||||||
|
ILogger<VerifyCreditWalletChargeCommandHandler> logger,
|
||||||
|
IUserPaymentLock paymentLock)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_paymentGateway = paymentGateway;
|
||||||
|
_logger = logger;
|
||||||
|
_paymentLock = paymentLock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> Handle(
|
||||||
|
VerifyCreditWalletChargeCommand request,
|
||||||
|
CancellationToken cancellationToken) =>
|
||||||
|
_paymentLock.ExecuteAsync(
|
||||||
|
PaymentLockScopes.Verify(request.UserId, request.Authority),
|
||||||
|
PaymentLockStrategy.WaitForRelease,
|
||||||
|
ct => HandleCore(request, ct),
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
private async Task<bool> HandleCore(
|
||||||
|
VerifyCreditWalletChargeCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Verifying credit wallet charge. UserId: {UserId}, Amount: {Amount}, Authority: {Authority}",
|
||||||
|
request.UserId,
|
||||||
|
request.Amount,
|
||||||
|
request.Authority);
|
||||||
|
|
||||||
|
var user = await _context.Users
|
||||||
|
.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken)
|
||||||
|
?? throw new NotFoundException(nameof(User), request.UserId);
|
||||||
|
|
||||||
|
var paymentTx = await _context.PaymentTransactions
|
||||||
|
.FirstOrDefaultAsync(pt => pt.Authority == request.Authority, cancellationToken);
|
||||||
|
|
||||||
|
if (paymentTx?.PaymentStatus == true)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("PaymentTransaction already verified: {Authority}", request.Authority);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var amountInToman = (decimal)(paymentTx?.Amount ?? 0);
|
||||||
|
|
||||||
|
var verifyResult = await _paymentGateway.VerifyPaymentAsync(
|
||||||
|
request.Authority,
|
||||||
|
"OK",
|
||||||
|
amountInToman,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
if (paymentTx != null)
|
||||||
|
{
|
||||||
|
paymentTx.PaymentStatus = verifyResult.IsSuccess;
|
||||||
|
paymentTx.VerificationStatusCode = verifyResult.VerificationCode;
|
||||||
|
paymentTx.VerificationStatusMessage = verifyResult.Message;
|
||||||
|
paymentTx.CardPan = verifyResult.CardPan;
|
||||||
|
paymentTx.CardHash = verifyResult.CardHash;
|
||||||
|
paymentTx.RefId = verifyResult.TrackingCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verifyResult.IsSuccess)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Credit wallet charge verification failed for UserId {UserId}: {Message}",
|
||||||
|
request.UserId,
|
||||||
|
verifyResult.Message);
|
||||||
|
|
||||||
|
throw new Exception($"تراکنش ناموفق: {verifyResult.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var wallet = await _context.UserWallets
|
||||||
|
.FirstOrDefaultAsync(w => w.UserId == user.Id, cancellationToken)
|
||||||
|
?? throw new NotFoundException($"کیف پول کاربر با شناسه {request.UserId} یافت نشد");
|
||||||
|
|
||||||
|
var oldBalance = wallet.Balance;
|
||||||
|
wallet.Balance += request.Amount;
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Charging credit balance for UserId {UserId}: {OldBalance} -> {NewBalance}",
|
||||||
|
request.UserId,
|
||||||
|
oldBalance,
|
||||||
|
wallet.Balance);
|
||||||
|
|
||||||
|
var transaction = new Transaction
|
||||||
|
{
|
||||||
|
Amount = request.Amount,
|
||||||
|
Description = $"شارژ کیف پول اصلی - کاربر {user.Id}",
|
||||||
|
PaymentStatus = PaymentStatus.Success,
|
||||||
|
PaymentDate = DateTime.Now,
|
||||||
|
RefId = verifyResult.RefId,
|
||||||
|
Type = TransactionType.CreditWalletCharge
|
||||||
|
};
|
||||||
|
|
||||||
|
_context.Transactions.Add(transaction);
|
||||||
|
await _context.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
_context.UserWalletHistories.Add(new Domain.Entities.UserWalletHistory
|
||||||
|
{
|
||||||
|
WalletId = wallet.Id,
|
||||||
|
CurrentBalance = wallet.Balance,
|
||||||
|
ChangeValue = request.Amount,
|
||||||
|
CurrentNetworkBalance = wallet.NetworkBalance,
|
||||||
|
ChangeNerworkValue = 0,
|
||||||
|
CurrentDiscountBalance = wallet.DiscountBalance,
|
||||||
|
ChangeDiscountValue = 0,
|
||||||
|
IsIncrease = true,
|
||||||
|
RefrenceId = transaction.Id
|
||||||
|
});
|
||||||
|
await _context.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (paymentTx != null)
|
||||||
|
{
|
||||||
|
paymentTx.TransactionId = transaction.Id;
|
||||||
|
await _context.SaveChangesAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"Credit wallet charged successfully. UserId: {UserId}, TransactionId: {TransactionId}, RefId: {RefId}",
|
||||||
|
user.Id,
|
||||||
|
transaction.Id,
|
||||||
|
verifyResult.RefId);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(
|
||||||
|
ex,
|
||||||
|
"Error in VerifyCreditWalletChargeCommand for UserId: {UserId}",
|
||||||
|
request.UserId);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,4 +36,9 @@ public enum TransactionType
|
|||||||
/// بونوس داخلی کیفپول جادویی (مبلغ × 1.5)
|
/// بونوس داخلی کیفپول جادویی (مبلغ × 1.5)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
MagicWalletBonus = 15,
|
MagicWalletBonus = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// شارژ کیف پول اصلی از درگاه
|
||||||
|
/// </summary>
|
||||||
|
CreditWalletCharge = 16,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using CMSMicroservice.Application.PackageCQ.Commands.VerifyUserPackagePurchasePa
|
|||||||
using CMSMicroservice.Application.Common.Interfaces;
|
using CMSMicroservice.Application.Common.Interfaces;
|
||||||
using CMSMicroservice.Application.DiscountShopCQ.Commands.CompleteOrderPayment;
|
using CMSMicroservice.Application.DiscountShopCQ.Commands.CompleteOrderPayment;
|
||||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge;
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge;
|
||||||
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge;
|
||||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge;
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge;
|
||||||
using CMSMicroservice.Domain.Entities;
|
using CMSMicroservice.Domain.Entities;
|
||||||
using CMSMicroservice.Domain.Entities.Payment;
|
using CMSMicroservice.Domain.Entities.Payment;
|
||||||
@@ -174,6 +175,19 @@ public class ZarinpalReconciliationJob
|
|||||||
}, ct);
|
}, ct);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "credit-wallet":
|
||||||
|
if (!paymentTx.UserId.HasValue)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"UserId is null for credit-wallet authority {authority}");
|
||||||
|
|
||||||
|
await _sender.Send(new VerifyCreditWalletChargeCommand
|
||||||
|
{
|
||||||
|
Authority = authority,
|
||||||
|
UserId = paymentTx.UserId.Value,
|
||||||
|
Amount = paymentTx.Amount
|
||||||
|
}, ct);
|
||||||
|
break;
|
||||||
|
|
||||||
case "discount-order":
|
case "discount-order":
|
||||||
await ReconcileDiscountOrderAsync(paymentTx, ct);
|
await ReconcileDiscountOrderAsync(paymentTx, ct);
|
||||||
break;
|
break;
|
||||||
@@ -194,6 +208,8 @@ public class ZarinpalReconciliationJob
|
|||||||
return "magic-wallet";
|
return "magic-wallet";
|
||||||
if (callbackUrl.Contains("type=discount-wallet", StringComparison.OrdinalIgnoreCase))
|
if (callbackUrl.Contains("type=discount-wallet", StringComparison.OrdinalIgnoreCase))
|
||||||
return "discount-wallet";
|
return "discount-wallet";
|
||||||
|
if (callbackUrl.Contains("type=credit-wallet", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return "credit-wallet";
|
||||||
if (callbackUrl.Contains("type=discount-order", StringComparison.OrdinalIgnoreCase))
|
if (callbackUrl.Contains("type=discount-order", StringComparison.OrdinalIgnoreCase))
|
||||||
return "discount-order";
|
return "discount-order";
|
||||||
// Package callbacks have orderId= but no type= parameter
|
// Package callbacks have orderId= but no type= parameter
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Version>0.0.201</Version>
|
<Version>0.0.202</Version>
|
||||||
<DebugType>None</DebugType>
|
<DebugType>None</DebugType>
|
||||||
<DebugSymbols>False</DebugSymbols>
|
<DebugSymbols>False</DebugSymbols>
|
||||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
|
|||||||
@@ -110,6 +110,21 @@ service UserWalletContract
|
|||||||
body: "*"
|
body: "*"
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ============= Credit (Main) Wallet Methods =============
|
||||||
|
|
||||||
|
rpc InitiateCreditCharge(InitiateCreditChargeRequest) returns (InitiateCreditChargeResponse){
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/Customer/InitiateCreditCharge"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
};
|
||||||
|
rpc VerifyCreditCharge(VerifyWalletChargeRequest) returns (VerifyWalletChargeResponse){
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/Customer/VerifyCreditCharge"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
message CreateNewUserWalletRequest
|
message CreateNewUserWalletRequest
|
||||||
{
|
{
|
||||||
@@ -283,6 +298,20 @@ message InitiateDiscountChargeResponse
|
|||||||
string error_message = 3;
|
string error_message = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============= Credit (Main) Wallet Messages =============
|
||||||
|
|
||||||
|
message InitiateCreditChargeRequest
|
||||||
|
{
|
||||||
|
int64 amount = 1; // مبلغ واریزی (تومان)
|
||||||
|
}
|
||||||
|
|
||||||
|
message InitiateCreditChargeResponse
|
||||||
|
{
|
||||||
|
bool is_success = 1;
|
||||||
|
string gateway_url = 2;
|
||||||
|
string error_message = 3;
|
||||||
|
}
|
||||||
|
|
||||||
// ============= Wallet Verify Messages =============
|
// ============= Wallet Verify Messages =============
|
||||||
|
|
||||||
message VerifyWalletChargeRequest
|
message VerifyWalletChargeRequest
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ using CMSMicroservice.Application.UserWalletCQ.Commands.UpdateUserWallet;
|
|||||||
using CMSMicroservice.Application.UserWalletCQ.Commands.DeleteUserWallet;
|
using CMSMicroservice.Application.UserWalletCQ.Commands.DeleteUserWallet;
|
||||||
using CMSMicroservice.Application.WalletCQ.Commands.ChargeMagicWallet;
|
using CMSMicroservice.Application.WalletCQ.Commands.ChargeMagicWallet;
|
||||||
using CMSMicroservice.Application.WalletCQ.Commands.ChargeDiscountWallet;
|
using CMSMicroservice.Application.WalletCQ.Commands.ChargeDiscountWallet;
|
||||||
|
using CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet;
|
||||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge;
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyMagicWalletCharge;
|
||||||
using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge;
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge;
|
||||||
|
using CMSMicroservice.Application.WalletCQ.Commands.VerifyCreditWalletCharge;
|
||||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetUserWallet;
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetUserWallet;
|
||||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetAllUserWalletByFilter;
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetAllUserWalletByFilter;
|
||||||
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWalletHistory;
|
using CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWalletHistory;
|
||||||
@@ -242,6 +244,38 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============= Credit (Main) Wallet Methods =============
|
||||||
|
|
||||||
|
public override async Task<InitiateCreditChargeResponse> InitiateCreditCharge(
|
||||||
|
InitiateCreditChargeRequest request, ServerCallContext context)
|
||||||
|
{
|
||||||
|
var userId = GetCurrentUserId();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await _sender.Send(new ChargeCreditWalletCommand
|
||||||
|
{
|
||||||
|
UserId = userId,
|
||||||
|
Amount = request.Amount
|
||||||
|
}, context.CancellationToken);
|
||||||
|
|
||||||
|
return new InitiateCreditChargeResponse
|
||||||
|
{
|
||||||
|
IsSuccess = result.IsSuccess,
|
||||||
|
GatewayUrl = result.GatewayUrl ?? "",
|
||||||
|
ErrorMessage = result.ErrorMessage ?? ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (PaymentInProgressException ex)
|
||||||
|
{
|
||||||
|
return new InitiateCreditChargeResponse
|
||||||
|
{
|
||||||
|
IsSuccess = false,
|
||||||
|
ErrorMessage = ex.Message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============= Wallet Verify Methods =============
|
// ============= Wallet Verify Methods =============
|
||||||
|
|
||||||
public override async Task<VerifyWalletChargeResponse> VerifyMagicCharge(
|
public override async Task<VerifyWalletChargeResponse> VerifyMagicCharge(
|
||||||
@@ -330,6 +364,57 @@ public class UserWalletService : UserWalletContract.UserWalletContractBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<VerifyWalletChargeResponse> VerifyCreditCharge(
|
||||||
|
VerifyWalletChargeRequest request, ServerCallContext context)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("VerifyCreditCharge called: Authority={Authority}, Status={Status}",
|
||||||
|
request.Authority, request.Status);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(request.Authority))
|
||||||
|
return new VerifyWalletChargeResponse { Success = false, Message = "کد Authority نامعتبر است" };
|
||||||
|
|
||||||
|
var paymentTx = await _context.PaymentTransactions
|
||||||
|
.FirstOrDefaultAsync(pt => pt.Authority == request.Authority, context.CancellationToken);
|
||||||
|
|
||||||
|
if (paymentTx == null || !paymentTx.UserId.HasValue)
|
||||||
|
{
|
||||||
|
_logger.LogError("VerifyCreditCharge: PaymentTransaction not found for Authority={Authority}", request.Authority);
|
||||||
|
return new VerifyWalletChargeResponse { Success = false, Message = "تراکنش یافت نشد" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.Equals(request.Status, "OK", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("VerifyCreditCharge: Payment cancelled by user. Authority={Authority}", request.Authority);
|
||||||
|
return new VerifyWalletChargeResponse { Success = false, Message = "پرداخت توسط کاربر لغو شد" };
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _sender.Send(new VerifyCreditWalletChargeCommand
|
||||||
|
{
|
||||||
|
UserId = paymentTx.UserId.Value,
|
||||||
|
Amount = paymentTx.Amount,
|
||||||
|
Authority = request.Authority
|
||||||
|
}, context.CancellationToken);
|
||||||
|
|
||||||
|
_logger.LogInformation("VerifyCreditCharge result: {Result}, Authority={Authority}, UserId={UserId}",
|
||||||
|
result, request.Authority, paymentTx.UserId.Value);
|
||||||
|
|
||||||
|
return new VerifyWalletChargeResponse
|
||||||
|
{
|
||||||
|
Success = result,
|
||||||
|
Message = result
|
||||||
|
? "شارژ کیف پول اصلی با موفقیت انجام شد"
|
||||||
|
: "شارژ کیف پول اصلی ناموفق بود"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "VerifyCreditCharge error: Authority={Authority}", request.Authority);
|
||||||
|
return new VerifyWalletChargeResponse { Success = false, Message = ex.Message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override async Task<GetMagicWalletStatusResponse> GetMagicWalletStatus(
|
public override async Task<GetMagicWalletStatusResponse> GetMagicWalletStatus(
|
||||||
Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user