diff --git a/src/CMSMicroservice.Infrastructure/Services/Payment/BankMellatPaymentService.cs b/src/CMSMicroservice.Infrastructure/Services/Payment/BankMellatPaymentService.cs
new file mode 100644
index 0000000..e47ae3b
--- /dev/null
+++ b/src/CMSMicroservice.Infrastructure/Services/Payment/BankMellatPaymentService.cs
@@ -0,0 +1,367 @@
+using CMSMicroservice.Application.Common.Interfaces;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Text;
+using System.Xml.Linq;
+
+namespace CMSMicroservice.Infrastructure.Services.Payment;
+
+///
+/// Real Implementation برای درگاه پرداخت بانک ملت (IPG)
+/// بانک ملت از SOAP Web Service استفاده میکند
+/// برای فعالسازی: باید TerminalId, Username, Password را در appsettings.json تنظیم کنید
+///
+public class BankMellatPaymentService : IPaymentGatewayService
+{
+ private readonly HttpClient _httpClient;
+ private readonly IConfiguration _configuration;
+ private readonly ILogger _logger;
+ private readonly string _terminalId;
+ private readonly string _username;
+ private readonly string _password;
+ private readonly string _serviceUrl;
+
+ public BankMellatPaymentService(
+ HttpClient httpClient,
+ IConfiguration configuration,
+ ILogger logger)
+ {
+ _httpClient = httpClient;
+ _configuration = configuration;
+ _logger = logger;
+
+ // خواندن تنظیمات از appsettings.json
+ _terminalId = _configuration["BankMellat:TerminalId"] ?? throw new InvalidOperationException(
+ "BankMellat:TerminalId is not configured");
+ _username = _configuration["BankMellat:Username"] ?? throw new InvalidOperationException(
+ "BankMellat:Username is not configured");
+ _password = _configuration["BankMellat:Password"] ?? throw new InvalidOperationException(
+ "BankMellat:Password is not configured");
+ _serviceUrl = _configuration["BankMellat:ServiceUrl"] ?? "https://bpm.shaparak.ir/pgwchannel/services/pgw";
+
+ _httpClient.Timeout = TimeSpan.FromSeconds(30);
+ }
+
+ public async Task InitiatePaymentAsync(
+ PaymentRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ _logger.LogInformation(
+ "Initiating Bank Mellat payment: UserId={UserId}, Amount={Amount}",
+ request.UserId, request.Amount);
+
+ // تبدیل مبلغ به ریال (بانک ملت ریال میخواهد)
+ var amountInRials = (long)(request.Amount * 10);
+ var localDate = DateTime.Now.ToString("yyyyMMdd");
+ var localTime = DateTime.Now.ToString("HHmmss");
+ var orderId = $"{request.UserId}_{DateTime.Now.Ticks}";
+
+ // ساخت SOAP Request
+ var soapRequest = $@"
+
+
+
+ {_terminalId}
+ {_username}
+ {_password}
+ {orderId}
+ {amountInRials}
+ {localDate}
+ {localTime}
+ {request.Description}
+ {request.CallbackUrl}
+ 0
+
+
+ ";
+
+ var content = new StringContent(soapRequest, Encoding.UTF8, "text/xml");
+ content.Headers.Add("SOAPAction", "http://interfaces.core.sw.bps.com/IPaymentGateway/bpPayRequest");
+
+ var response = await _httpClient.PostAsync(_serviceUrl, content, cancellationToken);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ _logger.LogError(
+ "Bank Mellat API error: StatusCode={StatusCode}",
+ response.StatusCode);
+
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = $"خطا در ارتباط با بانک ملت: {response.StatusCode}"
+ };
+ }
+
+ var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
+ var refId = ParseSoapResponse(responseContent, "return");
+
+ // بررسی کد خطا
+ if (string.IsNullOrEmpty(refId) || !long.TryParse(refId, out var refIdNumber))
+ {
+ _logger.LogError("Invalid RefId from Bank Mellat: {RefId}", refId);
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = "پاسخ نامعتبر از بانک ملت"
+ };
+ }
+
+ if (refIdNumber < 0)
+ {
+ var errorMessage = GetBankMellatErrorMessage(refIdNumber.ToString());
+ _logger.LogError("Bank Mellat error code: {ErrorCode} - {Message}", refIdNumber, errorMessage);
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = errorMessage
+ };
+ }
+
+ _logger.LogInformation(
+ "Bank Mellat payment initiated successfully: RefId={RefId}",
+ refId);
+
+ // URL درگاه بانک ملت
+ var gatewayUrl = $"https://bpm.shaparak.ir/pgwchannel/startpay.mellat?RefId={refId}";
+
+ return new PaymentInitiateResult
+ {
+ IsSuccess = true,
+ RefId = refId,
+ GatewayUrl = gatewayUrl,
+ ErrorMessage = null
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error in InitiatePaymentAsync");
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = "خطای غیرمنتظره در برقراری ارتباط با بانک"
+ };
+ }
+ }
+
+ public async Task VerifyPaymentAsync(
+ string refId,
+ string verificationToken,
+ CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ _logger.LogInformation("Verifying Bank Mellat payment: RefId={RefId}", refId);
+
+ // ساخت SOAP Request برای Verify
+ var soapRequest = $@"
+
+
+
+ {_terminalId}
+ {_username}
+ {_password}
+ {verificationToken}
+ {verificationToken}
+ {refId}
+
+
+ ";
+
+ var content = new StringContent(soapRequest, Encoding.UTF8, "text/xml");
+ content.Headers.Add("SOAPAction", "http://interfaces.core.sw.bps.com/IPaymentGateway/bpVerifyRequest");
+
+ var response = await _httpClient.PostAsync(_serviceUrl, content, cancellationToken);
+ var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
+ var result = ParseSoapResponse(responseContent, "return");
+
+ var isSuccess = result == "0"; // 0 = موفق
+
+ if (isSuccess)
+ {
+ // اگر Verify موفق بود، باید Settle کنیم
+ await SettlePaymentAsync(refId, verificationToken, cancellationToken);
+ }
+
+ _logger.LogInformation(
+ "Bank Mellat verification result: RefId={RefId}, IsSuccess={IsSuccess}",
+ refId, isSuccess);
+
+ return new PaymentVerificationResult
+ {
+ IsSuccess = isSuccess,
+ RefId = refId,
+ TrackingCode = refId,
+ Amount = 0, // مبلغ باید از Database بیاید
+ Message = isSuccess ? "تراکنش موفق" : GetBankMellatErrorMessage(result)
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error in VerifyPaymentAsync");
+ return new PaymentVerificationResult
+ {
+ IsSuccess = false,
+ RefId = refId,
+ Message = "خطا در تأیید پرداخت"
+ };
+ }
+ }
+
+ private async Task SettlePaymentAsync(string refId, string orderId, CancellationToken cancellationToken)
+ {
+ try
+ {
+ var soapRequest = $@"
+
+
+
+ {_terminalId}
+ {_username}
+ {_password}
+ {orderId}
+ {orderId}
+ {refId}
+
+
+ ";
+
+ var content = new StringContent(soapRequest, Encoding.UTF8, "text/xml");
+ content.Headers.Add("SOAPAction", "http://interfaces.core.sw.bps.com/IPaymentGateway/bpSettleRequest");
+
+ var response = await _httpClient.PostAsync(_serviceUrl, content, cancellationToken);
+ var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
+ var result = ParseSoapResponse(responseContent, "return");
+
+ var isSuccess = result == "0";
+ _logger.LogInformation(
+ "Bank Mellat settle result: RefId={RefId}, IsSuccess={IsSuccess}",
+ refId, isSuccess);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error in SettlePaymentAsync");
+ }
+ }
+
+ public async Task ProcessPayoutAsync(
+ PayoutRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ _logger.LogInformation(
+ "Processing Bank Mellat payout: UserId={UserId}, Amount={Amount}, IBAN={Iban}",
+ request.UserId, request.Amount, request.Iban);
+
+ // Validation
+ if (!request.Iban.StartsWith("IR") || request.Iban.Length != 26)
+ {
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "فرمت شماره شبا نامعتبر است",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ if (request.Amount < 10_000)
+ {
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "حداقل مبلغ برداشت 10,000 تومان است",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ // TODO: بانک ملت ممکن است API واریز مستقیم نداشته باشد
+ // در این صورت باید از Shaparak Paya (سامانه پایا) استفاده کرد
+ // یا از سرویسهای واسط مانند Fanapay, IPG.ir استفاده شود
+
+ _logger.LogWarning(
+ "Bank Mellat direct payout is not supported. Use Shaparak Paya or third-party service.");
+
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "واریز مستقیم از طریق بانک ملت پشتیبانی نمیشود. از سامانه پایا استفاده کنید.",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error in ProcessPayoutAsync");
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "خطا در پردازش واریز",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+ }
+
+ // Helper method to parse SOAP XML response
+ private string ParseSoapResponse(string soapResponse, string elementName)
+ {
+ try
+ {
+ var doc = XDocument.Parse(soapResponse);
+ var ns = doc.Root?.GetDefaultNamespace();
+ var element = doc.Descendants(ns + elementName).FirstOrDefault();
+ return element?.Value ?? string.Empty;
+ }
+ catch
+ {
+ return string.Empty;
+ }
+ }
+
+ // کدهای خطای بانک ملت
+ private string GetBankMellatErrorMessage(string errorCode)
+ {
+ return errorCode switch
+ {
+ "0" => "تراکنش موفق",
+ "11" => "شماره کارت نامعتبر است",
+ "12" => "موجودی کافی نیست",
+ "13" => "رمز نادرست است",
+ "14" => "تعداد دفعات وارد کردن رمز بیش از حد مجاز است",
+ "15" => "کارت نامعتبر است",
+ "16" => "دفعات برداشت وجه بیش از حد مجاز است",
+ "17" => "کاربر از انجام تراکنش منصرف شده است",
+ "18" => "تاریخ انقضای کارت گذشته است",
+ "19" => "مبلغ برداشت وجه بیش از حد مجاز است",
+ "21" => "پذیرنده نامعتبر است",
+ "23" => "خطای امنیتی رخ داده است",
+ "24" => "اطلاعات کاربری پذیرنده نامعتبر است",
+ "25" => "مبلغ نامعتبر است",
+ "31" => "پاسخ نامعتبر است",
+ "32" => "فرمت اطلاعات وارد شده صحیح نمیباشد",
+ "33" => "حساب نامعتبر است",
+ "34" => "خطای سیستمی",
+ "35" => "تاریخ نامعتبر است",
+ "41" => "شماره درخواست تکراری است",
+ "42" => "تراکنش یافت نشد",
+ "43" => "قبلا درخواست Verify داده شده است",
+ "44" => "درخواست Verify یافت نشد",
+ "45" => "تراکنش Settle شده است",
+ "46" => "تراکنش Settle نشده است",
+ "47" => "تراکنش Settle یافت نشد",
+ "48" => "تراکنش Reverse شده است",
+ "49" => "تراکنش Refund یافت نشد",
+ "51" => "تراکنش تکراری است",
+ "54" => "تراکنش مرجع موجود نیست",
+ "55" => "تراکنش نامعتبر است",
+ "61" => "خطا در واریز",
+ _ => $"خطای ناشناخته: {errorCode}"
+ };
+ }
+}
diff --git a/src/CMSMicroservice.Infrastructure/Services/Payment/DayaPaymentService.cs b/src/CMSMicroservice.Infrastructure/Services/Payment/DayaPaymentService.cs
new file mode 100644
index 0000000..b6bb4a4
--- /dev/null
+++ b/src/CMSMicroservice.Infrastructure/Services/Payment/DayaPaymentService.cs
@@ -0,0 +1,318 @@
+using CMSMicroservice.Application.Common.Interfaces;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Text.Json;
+
+namespace CMSMicroservice.Infrastructure.Services.Payment;
+
+///
+/// Real Implementation برای درگاه پرداخت دایا
+/// برای فعالسازی: باید URL و API Key را در appsettings.json تنظیم کنید
+///
+public class DayaPaymentService : IPaymentGatewayService
+{
+ private readonly HttpClient _httpClient;
+ private readonly IConfiguration _configuration;
+ private readonly ILogger _logger;
+ private readonly string _apiKey;
+ private readonly string _baseUrl;
+
+ public DayaPaymentService(
+ HttpClient httpClient,
+ IConfiguration configuration,
+ ILogger logger)
+ {
+ _httpClient = httpClient;
+ _configuration = configuration;
+ _logger = logger;
+
+ // خواندن تنظیمات از appsettings.json
+ _baseUrl = _configuration["DayaPayment:BaseUrl"] ?? "https://api.daya.ir";
+ _apiKey = _configuration["DayaPayment:ApiKey"] ?? throw new InvalidOperationException(
+ "DayaPayment:ApiKey is not configured in appsettings.json");
+
+ _httpClient.BaseAddress = new Uri(_baseUrl);
+ _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
+ _httpClient.Timeout = TimeSpan.FromSeconds(30);
+ }
+
+ public async Task InitiatePaymentAsync(
+ PaymentRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ _logger.LogInformation(
+ "Initiating Daya payment: UserId={UserId}, Amount={Amount}",
+ request.UserId, request.Amount);
+
+ // ساختار Request برای API دایا
+ var apiRequest = new
+ {
+ amount = request.Amount,
+ mobile = request.Mobile,
+ description = request.Description,
+ callback_url = request.CallbackUrl,
+ user_id = request.UserId
+ };
+
+ var response = await _httpClient.PostAsJsonAsync(
+ "/api/v1/payment/initiate",
+ apiRequest,
+ cancellationToken);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync(cancellationToken);
+ _logger.LogError(
+ "Daya API error: StatusCode={StatusCode}, Error={Error}",
+ response.StatusCode, errorContent);
+
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = $"خطا در ارتباط با درگاه: {response.StatusCode}"
+ };
+ }
+
+ var result = await response.Content.ReadFromJsonAsync(cancellationToken);
+
+ if (result == null || string.IsNullOrEmpty(result.RefId))
+ {
+ _logger.LogError("Invalid response from Daya API");
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = "پاسخ نامعتبر از درگاه"
+ };
+ }
+
+ _logger.LogInformation(
+ "Daya payment initiated successfully: RefId={RefId}",
+ result.RefId);
+
+ return new PaymentInitiateResult
+ {
+ IsSuccess = true,
+ RefId = result.RefId,
+ GatewayUrl = result.GatewayUrl,
+ ErrorMessage = null
+ };
+ }
+ catch (HttpRequestException ex)
+ {
+ _logger.LogError(ex, "Network error while calling Daya API");
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = "خطا در ارتباط با سرور درگاه"
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Unexpected error in InitiatePaymentAsync");
+ return new PaymentInitiateResult
+ {
+ IsSuccess = false,
+ ErrorMessage = "خطای غیرمنتظره"
+ };
+ }
+ }
+
+ public async Task VerifyPaymentAsync(
+ string refId,
+ string verificationToken,
+ CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ _logger.LogInformation("Verifying Daya payment: RefId={RefId}", refId);
+
+ var apiRequest = new
+ {
+ ref_id = refId,
+ token = verificationToken
+ };
+
+ var response = await _httpClient.PostAsJsonAsync(
+ "/api/v1/payment/verify",
+ apiRequest,
+ cancellationToken);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync(cancellationToken);
+ _logger.LogError(
+ "Daya verification error: StatusCode={StatusCode}, Error={Error}",
+ response.StatusCode, errorContent);
+
+ return new PaymentVerificationResult
+ {
+ IsSuccess = false,
+ RefId = refId,
+ Message = $"خطا در تأیید پرداخت: {response.StatusCode}"
+ };
+ }
+
+ var result = await response.Content.ReadFromJsonAsync(cancellationToken);
+
+ if (result == null)
+ {
+ return new PaymentVerificationResult
+ {
+ IsSuccess = false,
+ RefId = refId,
+ Message = "پاسخ نامعتبر از درگاه"
+ };
+ }
+
+ _logger.LogInformation(
+ "Daya payment verified: RefId={RefId}, IsSuccess={IsSuccess}, TrackingCode={TrackingCode}",
+ refId, result.IsSuccess, result.TrackingCode);
+
+ return new PaymentVerificationResult
+ {
+ IsSuccess = result.IsSuccess,
+ RefId = refId,
+ TrackingCode = result.TrackingCode,
+ Amount = result.Amount,
+ Message = result.Message
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error in VerifyPaymentAsync");
+ return new PaymentVerificationResult
+ {
+ IsSuccess = false,
+ RefId = refId,
+ Message = "خطا در تأیید پرداخت"
+ };
+ }
+ }
+
+ public async Task ProcessPayoutAsync(
+ PayoutRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ try
+ {
+ _logger.LogInformation(
+ "Processing Daya payout: UserId={UserId}, Amount={Amount}, IBAN={Iban}",
+ request.UserId, request.Amount, request.Iban);
+
+ // Validation
+ if (!request.Iban.StartsWith("IR") || request.Iban.Length != 26)
+ {
+ _logger.LogWarning("Invalid IBAN format: {Iban}", request.Iban);
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "فرمت شماره شبا نامعتبر است",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ if (request.Amount < 10_000)
+ {
+ _logger.LogWarning("Amount too low: {Amount}", request.Amount);
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "حداقل مبلغ برداشت 10,000 تومان است",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ var apiRequest = new
+ {
+ amount = request.Amount,
+ iban = request.Iban,
+ account_holder_name = request.AccountHolderName,
+ description = request.Description,
+ internal_ref_id = request.InternalRefId,
+ user_id = request.UserId
+ };
+
+ var response = await _httpClient.PostAsJsonAsync(
+ "/api/v1/payout/process",
+ apiRequest,
+ cancellationToken);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ var errorContent = await response.Content.ReadAsStringAsync(cancellationToken);
+ _logger.LogError(
+ "Daya payout error: StatusCode={StatusCode}, Error={Error}",
+ response.StatusCode, errorContent);
+
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = $"خطا در واریز: {response.StatusCode}",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ var result = await response.Content.ReadFromJsonAsync(cancellationToken);
+
+ if (result == null)
+ {
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "پاسخ نامعتبر از درگاه",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ _logger.LogInformation(
+ "Daya payout processed: IsSuccess={IsSuccess}, BankRefId={BankRefId}",
+ result.IsSuccess, result.BankRefId);
+
+ return new PayoutResult
+ {
+ IsSuccess = result.IsSuccess,
+ BankRefId = result.BankRefId,
+ TrackingCode = result.TrackingCode,
+ Message = result.Message,
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error in ProcessPayoutAsync");
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "خطا در پردازش واریز",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+ }
+
+ // DTO classes for Daya API
+ private class DayaInitiateResponse
+ {
+ public string RefId { get; set; } = string.Empty;
+ public string GatewayUrl { get; set; } = string.Empty;
+ }
+
+ private class DayaVerifyResponse
+ {
+ public bool IsSuccess { get; set; }
+ public string TrackingCode { get; set; } = string.Empty;
+ public decimal Amount { get; set; }
+ public string Message { get; set; } = string.Empty;
+ }
+
+ private class DayaPayoutResponse
+ {
+ public bool IsSuccess { get; set; }
+ public string BankRefId { get; set; } = string.Empty;
+ public string TrackingCode { get; set; } = string.Empty;
+ public string Message { get; set; } = string.Empty;
+ }
+}
diff --git a/src/CMSMicroservice.Infrastructure/Services/Payment/MockPaymentGatewayService.cs b/src/CMSMicroservice.Infrastructure/Services/Payment/MockPaymentGatewayService.cs
new file mode 100644
index 0000000..88c0eee
--- /dev/null
+++ b/src/CMSMicroservice.Infrastructure/Services/Payment/MockPaymentGatewayService.cs
@@ -0,0 +1,127 @@
+using CMSMicroservice.Application.Common.Interfaces;
+using Microsoft.Extensions.Logging;
+
+namespace CMSMicroservice.Infrastructure.Services.Payment;
+
+///
+/// Mock Implementation برای شبیهسازی درگاه پرداخت
+/// این سرویس فقط برای تست و توسعه است
+///
+public class MockPaymentGatewayService : IPaymentGatewayService
+{
+ private readonly ILogger _logger;
+
+ public MockPaymentGatewayService(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ public async Task InitiatePaymentAsync(
+ PaymentRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ _logger.LogWarning("⚠️ Using MOCK Payment Gateway - Replace with real implementation in production!");
+
+ // شبیهسازی تاخیر شبکه
+ await Task.Delay(200, cancellationToken);
+
+ // شبیهسازی RefId
+ var refId = $"MOCK-PAY-{DateTime.Now.Ticks}";
+
+ _logger.LogInformation("Mock payment initiated: RefId={RefId}, Amount={Amount}, User={UserId}",
+ refId, request.Amount, request.UserId);
+
+ return new PaymentInitiateResult
+ {
+ IsSuccess = true,
+ RefId = refId,
+ GatewayUrl = $"https://mock-gateway.local/pay?ref={refId}",
+ ErrorMessage = null
+ };
+ }
+
+ public async Task VerifyPaymentAsync(
+ string refId,
+ string verificationToken,
+ CancellationToken cancellationToken = default)
+ {
+ _logger.LogWarning("⚠️ Using MOCK Payment Gateway - Verification");
+
+ // شبیهسازی تاخیر شبکه
+ await Task.Delay(150, cancellationToken);
+
+ // شبیهسازی: همه تراکنشها موفق هستند
+ var isSuccess = true;
+ var trackingCode = $"TRK-{DateTime.Now.Ticks}";
+
+ if (isSuccess)
+ {
+ _logger.LogInformation("Mock payment verified successfully: RefId={RefId}, Tracking={TrackingCode}",
+ refId, trackingCode);
+ }
+ else
+ {
+ _logger.LogWarning("Mock payment verification failed: RefId={RefId}", refId);
+ }
+
+ return new PaymentVerificationResult
+ {
+ IsSuccess = isSuccess,
+ RefId = refId,
+ TrackingCode = trackingCode,
+ Amount = 0, // باید از Database بیاید
+ Message = isSuccess ? "تراکنش موفق (Mock)" : "تراکنش ناموفق (Mock)"
+ };
+ }
+
+ public async Task ProcessPayoutAsync(
+ PayoutRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ _logger.LogWarning("⚠️ Using MOCK Payment Gateway - Payout");
+
+ // شبیهسازی تاخیر شبکه
+ await Task.Delay(300, cancellationToken);
+
+ // Validation: چک کردن شبا (باید IR بخوره و 26 کاراکتر باشد)
+ if (!request.Iban.StartsWith("IR") || request.Iban.Length != 26)
+ {
+ _logger.LogError("Invalid IBAN format: {Iban}", request.Iban);
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "فرمت شماره شبا نامعتبر است",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ // Validation: چک کردن مبلغ (حداقل 10,000 تومان)
+ if (request.Amount < 10_000)
+ {
+ _logger.LogError("Payout amount too low: {Amount}", request.Amount);
+ return new PayoutResult
+ {
+ IsSuccess = false,
+ Message = "حداقل مبلغ برداشت 10,000 تومان است",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+
+ // شبیهسازی: همه واریزها موفق هستند
+ var bankRefId = $"BANK-{DateTime.Now.Ticks}";
+ var trackingCode = $"TRK-PAYOUT-{DateTime.Now.Ticks}";
+
+ _logger.LogInformation(
+ "Mock payout processed successfully: User={UserId}, Amount={Amount}, IBAN={Iban}, BankRef={BankRefId}",
+ request.UserId, request.Amount, request.Iban, bankRefId);
+
+ return new PayoutResult
+ {
+ IsSuccess = true,
+ BankRefId = bankRefId,
+ TrackingCode = trackingCode,
+ Message = $"واریز {request.Amount:N0} تومان به حساب {request.Iban} با موفقیت انجام شد (Mock)",
+ ProcessedAt = DateTime.UtcNow
+ };
+ }
+}