fix: Toman/Rial — system uses Toman everywhere, only ZarinPal gets Rial
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 10m16s

Core change in ZarinPalPaymentService:
- InitiatePaymentAsync: Amount (Toman) × 10 → Rial for gateway
- VerifyPaymentWithAmountAsync: Amount (Toman) × 10 → Rial for verify
- Verify result: gateway Rial ÷ 10 → Toman back to system

Also fixed:
- Package.Price doc: ریال → تومان
- Error messages in 3 handlers: ریال → تومان
- ConfigurationService descriptions: ریال → تومان (7 entries)
- Notification SMS/email: ریال → تومان
- Doc comments in 5 command files: ریال → تومان
- PaymentCallback comments: ریال → تومان

14 files changed across Domain, Application, Infrastructure, WebApi
This commit is contained in:
masoodafar-web
2026-02-27 21:03:27 +03:30
parent 61b7e4f8f2
commit aee7b59fc1
14 changed files with 36 additions and 32 deletions
@@ -150,7 +150,7 @@ public class ActivateClubMembershipCommandHandler : IRequestHandler<ActivateClub
if (wallet.Balance < package.Price) if (wallet.Balance < package.Price)
{ {
throw new BadRequestException( throw new BadRequestException(
$"برای فعالسازی باشگاه مشتریان باید حداقل {package.Price:N0} ریال موجودی اصلی داشته باشید" $"برای فعالسازی باشگاه مشتریان باید حداقل {package.Price:N0} تومان موجودی اصلی داشته باشید"
); );
} }
} }
@@ -118,7 +118,7 @@ public class PlaceOrderCommandHandler : IRequestHandler<PlaceOrderCommand, Place
return new PlaceOrderResponseDto return new PlaceOrderResponseDto
{ {
Success = false, Success = false,
Message = $"موجودی کیف پول اعتباری کافی نیست. مبلغ مورد نیاز: {maxDiscountBalanceUsable:N0} ریال، موجودی شما: {userWallet.DiscountBalance:N0} ریال" Message = $"موجودی کیف پول اعتباری کافی نیست. مبلغ مورد نیاز: {maxDiscountBalanceUsable:N0} تومان، موجودی شما: {userWallet.DiscountBalance:N0} تومان"
}; };
} }
@@ -14,7 +14,7 @@ public class CreateManualPaymentCommand : IRequest<long>
public long UserId { get; set; } public long UserId { get; set; }
/// <summary> /// <summary>
/// مبلغ تراکنش (ریال) /// مبلغ تراکنش (تومان)
/// </summary> /// </summary>
public long Amount { get; set; } public long Amount { get; set; }
@@ -8,7 +8,7 @@ public record ProcessManualMembershipPaymentCommand : IRequest<ProcessManualMemb
public long UserId { get; init; } public long UserId { get; init; }
/// <summary> /// <summary>
/// مبلغ پرداختی (ریال) /// مبلغ پرداختی (تومان)
/// </summary> /// </summary>
public long Amount { get; init; } public long Amount { get; init; }
@@ -3,7 +3,7 @@ namespace CMSMicroservice.Application.UserWalletCQ.Queries.GetCustomerWithdrawal
public class GetCustomerWithdrawalSettingsResponseDto public class GetCustomerWithdrawalSettingsResponseDto
{ {
/// <summary> /// <summary>
/// حداقل مبلغ برداشت (ریال) /// حداقل مبلغ برداشت (تومان)
/// </summary> /// </summary>
public long MinWithdrawalAmount { get; set; } public long MinWithdrawalAmount { get; set; }
} }
@@ -15,7 +15,7 @@ public class ChargeDiscountWalletCommand : IRequest<PaymentInitiateResult>
public long UserId { get; set; } public long UserId { get; set; }
/// <summary> /// <summary>
/// مبلغ مورد نظر برای شارژ (ریال) /// مبلغ مورد نظر برای شارژ (تومان)
/// </summary> /// </summary>
public long Amount { get; set; } public long Amount { get; set; }
} }
@@ -15,7 +15,7 @@ public class ChargeMagicWalletCommand : IRequest<PaymentInitiateResult>
public long UserId { get; set; } public long UserId { get; set; }
/// <summary> /// <summary>
/// مبلغ واریزی واقعی (ریال) — اعتبار = مبلغ × 2.5 /// مبلغ واریزی واقعی (تومان) — اعتبار = مبلغ × 2.5
/// </summary> /// </summary>
public long Amount { get; set; } public long Amount { get; set; }
} }
@@ -109,7 +109,7 @@ public class ChargeMagicWalletCommandHandler
remainingDeposit remainingDeposit
); );
throw new BadRequestException( throw new BadRequestException(
$"مبلغ واریزی بیش از سقف باقیمانده است. حداکثر مبلغ قابل واریز: {remainingDeposit:N0} ریال" $"مبلغ واریزی بیش از سقف باقیمانده است. حداکثر مبلغ قابل واریز: {remainingDeposit:N0} تومان"
); );
} }
@@ -57,7 +57,7 @@ public class VerifyMagicWalletChargeCommandHandler
var userId = paymentTx.UserId var userId = paymentTx.UserId
?? throw new BadRequestException("شناسه کاربر در تراکنش پرداخت یافت نشد"); ?? throw new BadRequestException("شناسه کاربر در تراکنش پرداخت یافت نشد");
var depositAmount = paymentTx.Amount; // مبلغ واقعی واریزی (ریال) var depositAmount = paymentTx.Amount; // مبلغ واقعی واریزی (تومان)
// 2. بررسی وضعیت برگشتی از درگاه // 2. بررسی وضعیت برگشتی از درگاه
if (!string.Equals(request.Status, "OK", StringComparison.OrdinalIgnoreCase)) if (!string.Equals(request.Status, "OK", StringComparison.OrdinalIgnoreCase))
@@ -74,7 +74,7 @@ public class VerifyMagicWalletChargeCommandHandler
throw new BadRequestException("پرداخت توسط کاربر لغو شد"); throw new BadRequestException("پرداخت توسط کاربر لغو شد");
} }
// 3. Verify با درگاه (مبلغ به ریال) // 3. Verify با درگاه (مبلغ به تومان — تبدیل به ریال در ZarinPalService)
var verifyResult = await _paymentGateway.VerifyPaymentAsync( var verifyResult = await _paymentGateway.VerifyPaymentAsync(
request.Authority, request.Authority,
request.Status, request.Status,
@@ -19,7 +19,7 @@ public class Package : BaseAuditableEntity, IHasHistory<History.PackageHistory>
/// <summary>آدرس تصویر</summary> /// <summary>آدرس تصویر</summary>
public string ImagePath { get; set; } public string ImagePath { get; set; }
/// <summary>قیمت پکیج (ریال)</summary> /// <summary>قیمت پکیج (تومان)</summary>
public long Price { get; set; } public long Price { get; set; }
// === فیلدهای جدید v3 === // === فیلدهای جدید v3 ===
@@ -78,7 +78,7 @@ public class UserNotificationService : IUserNotificationService
var emailSubject = $"واریز کمیسیون هفته {weekNumber}{packageInfo}"; var emailSubject = $"واریز کمیسیون هفته {weekNumber}{packageInfo}";
var emailBody = "<div dir='rtl' style='font-family: Tahoma, Arial; text-align: right;'>" + var emailBody = "<div dir='rtl' style='font-family: Tahoma, Arial; text-align: right;'>" +
$"<h2>سلام {userFullName}</h2>" + $"<h2>سلام {userFullName}</h2>" +
$"<p>کمیسیون هفته {weekNumber} شما{packageInfo} به مبلغ <strong>{formattedAmount} ریال</strong> به کیف پول شما واریز شد.</p>" + $"<p>کمیسیون هفته {weekNumber} شما{packageInfo} به مبلغ <strong>{formattedAmount} تومان</strong> به کیف پول شما واریز شد.</p>" +
"<p>از اعتماد شما سپاسگزاریم.</p>" + "<p>از اعتماد شما سپاسگزاریم.</p>" +
"<hr/>" + "<hr/>" +
"<p style='color: #666; font-size: 12px;'>FourSat - سیستم مدیریت باشگاه مشتریان</p>" + "<p style='color: #666; font-size: 12px;'>FourSat - سیستم مدیریت باشگاه مشتریان</p>" +
@@ -97,7 +97,7 @@ public class UserNotificationService : IUserNotificationService
{ {
await SendSmsAsync( await SendSmsAsync(
phoneNumber: user.Mobile, phoneNumber: user.Mobile,
message: $"سلام {userFullName}\nکمیسیون هفته {weekNumber} شما{packageInfo} به مبلغ {formattedAmount} ریال واریز شد.\nFourSat", message: $"سلام {userFullName}\nکمیسیون هفته {weekNumber} شما{packageInfo} به مبلغ {formattedAmount} تومان واریز شد.\nFourSat",
cancellationToken: cancellationToken); cancellationToken: cancellationToken);
} }
@@ -66,8 +66,9 @@ public class ZarinPalPaymentService : IPaymentGatewayService
{ {
try try
{ {
// مبلغ از caller به ریال می‌رسد — مستقیم ارسال به زرین‌پال // مبلغ از caller به تومان می‌رسد — تبدیل به ریال برای زرین‌پال (×10)
var amountInRials = (long)request.Amount; var amountInToman = (long)request.Amount;
var amountInRials = amountInToman * 10;
var zarinPalRequest = new ZarinPalPaymentRequest var zarinPalRequest = new ZarinPalPaymentRequest
{ {
@@ -85,8 +86,8 @@ public class ZarinPalPaymentService : IPaymentGatewayService
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
_logger.LogInformation( _logger.LogInformation(
"ZarinPal payment request: Amount={AmountRial} Rial ({AmountToman} Toman), User={UserId}, Sandbox={Sandbox}", "ZarinPal payment request: Amount={AmountToman} Toman ({AmountRial} Rial), User={UserId}, Sandbox={Sandbox}",
amountInRials, amountInRials / 10m, request.UserId, _useSandbox); amountInToman, amountInRials, request.UserId, _useSandbox);
var response = await _httpClient.PostAsync(RequestEndpoint, content, cancellationToken); var response = await _httpClient.PostAsync(RequestEndpoint, content, cancellationToken);
var responseBody = await response.Content.ReadAsStringAsync(cancellationToken); var responseBody = await response.Content.ReadAsStringAsync(cancellationToken);
@@ -167,7 +168,7 @@ public class ZarinPalPaymentService : IPaymentGatewayService
/// <summary> /// <summary>
/// تأیید پرداخت با مبلغ — نسخه اصلی برای زرین‌پال /// تأیید پرداخت با مبلغ — نسخه اصلی برای زرین‌پال
/// refId = Authority، verificationToken = Status (OK/NOK)، amount = مبلغ به ریال /// refId = Authority، verificationToken = Status (OK/NOK)، amount = مبلغ به تومان
/// </summary> /// </summary>
public Task<PaymentVerificationResult> VerifyPaymentAsync( public Task<PaymentVerificationResult> VerifyPaymentAsync(
string refId, string refId,
@@ -181,7 +182,7 @@ public class ZarinPalPaymentService : IPaymentGatewayService
private async Task<PaymentVerificationResult> VerifyPaymentWithAmountAsync( private async Task<PaymentVerificationResult> VerifyPaymentWithAmountAsync(
string refId, string refId,
string verificationToken, string verificationToken,
decimal amountInRials, decimal amountInToman,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
try try
@@ -198,18 +199,21 @@ public class ZarinPalPaymentService : IPaymentGatewayService
}; };
} }
// تبدیل تومان به ریال برای زرین‌پال (×10)
var amountInRials = (long)(amountInToman * 10);
var verifyRequest = new ZarinPalVerifyRequest var verifyRequest = new ZarinPalVerifyRequest
{ {
MerchantId = _merchantId, MerchantId = _merchantId,
Authority = refId, Authority = refId,
Amount = (long)amountInRials Amount = amountInRials
}; };
var jsonContent = JsonSerializer.Serialize(verifyRequest, JsonOptions); var jsonContent = JsonSerializer.Serialize(verifyRequest, JsonOptions);
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
_logger.LogInformation("ZarinPal verify request: Authority={Authority}, Amount={Amount} Rial ({AmountToman} Toman)", _logger.LogInformation("ZarinPal verify request: Authority={Authority}, Amount={AmountToman} Toman ({AmountRial} Rial)",
refId, (long)amountInRials, amountInRials / 10m); refId, (long)amountInToman, amountInRials);
var response = await _httpClient.PostAsync(VerifyEndpoint, content, cancellationToken); var response = await _httpClient.PostAsync(VerifyEndpoint, content, cancellationToken);
var responseBody = await response.Content.ReadAsStringAsync(cancellationToken); var responseBody = await response.Content.ReadAsStringAsync(cancellationToken);
@@ -231,7 +235,7 @@ public class ZarinPalPaymentService : IPaymentGatewayService
IsSuccess = true, IsSuccess = true,
RefId = refId, RefId = refId,
TrackingCode = result.Data.RefId?.ToString(), TrackingCode = result.Data.RefId?.ToString(),
Amount = result.Data.Amount ?? 0, // ریال — بدون تبدیل Amount = (result.Data.Amount ?? 0) / 10, // تبدیل ریال → تومان
CardPan = result.Data.CardPan, CardPan = result.Data.CardPan,
CardHash = result.Data.CardHash, CardHash = result.Data.CardHash,
VerificationCode = result.Data.Code, VerificationCode = result.Data.Code,
@@ -82,11 +82,11 @@ public class PaymentCallbackController : ControllerBase
if (string.Equals(status, "OK", StringComparison.OrdinalIgnoreCase) if (string.Equals(status, "OK", StringComparison.OrdinalIgnoreCase)
&& !string.IsNullOrEmpty(authority)) && !string.IsNullOrEmpty(authority))
{ {
// Verify با مبلغ از دیتابیس (ریال) // Verify با مبلغ از دیتابیس (تومان — تبدیل به ریال در ZarinPalService)
var verifyResult = await _paymentGateway.VerifyPaymentAsync( var verifyResult = await _paymentGateway.VerifyPaymentAsync(
authority, authority,
status!, status!,
order.GatewayAmountPaid, // مبلغ به ریال order.GatewayAmountPaid, // مبلغ به تومان
cancellationToken); cancellationToken);
paymentSuccess = verifyResult.IsSuccess; paymentSuccess = verifyResult.IsSuccess;
@@ -223,20 +223,20 @@ public class ConfigurationService : ConfigurationContract.ConfigurationContractB
{ {
return key switch return key switch
{ {
"Club.ActivationFee" => "هزینه فعال‌سازی عضویت باشگاه (ریال)", "Club.ActivationFee" => "هزینه فعال‌سازی عضویت باشگاه (تومان)",
"Club.MembershipGiftValue" => "مبلغ هدیه حق عضویت باشگاه (ریال)", "Club.MembershipGiftValue" => "مبلغ هدیه حق عضویت باشگاه (تومان)",
"Commission.MinWithdrawalAmount" => "حداقل مبلغ برداشت (ریال)", "Commission.MinWithdrawalAmount" => "حداقل مبلغ برداشت (تومان)",
"Commission.MaxWeeklyBalancesPerLeg" => "سقف تعادل هفتگی برای هر دست", "Commission.MaxWeeklyBalancesPerLeg" => "سقف تعادل هفتگی برای هر دست",
"Commission.MaxNetworkLevel" => "حداکثر عمق شبکه برای محاسبه کمیسیون", "Commission.MaxNetworkLevel" => "حداکثر عمق شبکه برای محاسبه کمیسیون",
"Commission.CashWithdrawalEnabled" => "امکان برداشت نقدی", "Commission.CashWithdrawalEnabled" => "امکان برداشت نقدی",
"Commission.CalculationStrategy" => "روش محاسبه کمیسیون", "Commission.CalculationStrategy" => "روش محاسبه کمیسیون",
"Network.AllowOrphanNodes" => "اجازه حذف والدین با فرزند", "Network.AllowOrphanNodes" => "اجازه حذف والدین با فرزند",
"Network.MaxChildrenPerLeg" => "حداکثر تعداد فرزند مستقیم در هر پا", "Network.MaxChildrenPerLeg" => "حداکثر تعداد فرزند مستقیم در هر پا",
"Package.BasePackageAmount" => "مبلغ پکیج پایه (ریال)", "Package.BasePackageAmount" => "مبلغ پکیج پایه (تومان)",
"Package.DayaLoanAmount" => "مبلغ وام دایا (ریال)", "Package.DayaLoanAmount" => "مبلغ وام دایا (تومان)",
"MagicWallet.Multiplier" => "ضریب شارژ کیف‌پول جادویی", "MagicWallet.Multiplier" => "ضریب شارژ کیف‌پول جادویی",
"MagicWallet.MaxDeposit" => "سقف واریز هر دور جادویی (ریال)", "MagicWallet.MaxDeposit" => "سقف واریز هر دور جادویی (تومان)",
"MagicWallet.MaxCredit" => "سقف اعتبار هر دور جادویی (ریال)", "MagicWallet.MaxCredit" => "سقف اعتبار هر دور جادویی (تومان)",
"System.MaintenanceMode" => "حالت تعمیر و نگهداری سیستم", "System.MaintenanceMode" => "حالت تعمیر و نگهداری سیستم",
"System.EnableAuditLog" => "فعال‌سازی لاگ تغییرات", "System.EnableAuditLog" => "فعال‌سازی لاگ تغییرات",
"Shop.VAT" => "مالیات بر ارزش افزوده", "Shop.VAT" => "مالیات بر ارزش افزوده",