319 lines
11 KiB
C#
319 lines
11 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Real Implementation برای درگاه پرداخت دایا
|
|
/// برای فعالسازی: باید URL و API Key را در appsettings.json تنظیم کنید
|
|
/// </summary>
|
|
public class DayaPaymentService : IPaymentGatewayService
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly IConfiguration _configuration;
|
|
private readonly ILogger<DayaPaymentService> _logger;
|
|
private readonly string _apiKey;
|
|
private readonly string _baseUrl;
|
|
|
|
public DayaPaymentService(
|
|
HttpClient httpClient,
|
|
IConfiguration configuration,
|
|
ILogger<DayaPaymentService> 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<PaymentInitiateResult> 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<DayaInitiateResponse>(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<PaymentVerificationResult> 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<DayaVerifyResponse>(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<PayoutResult> 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.Now
|
|
};
|
|
}
|
|
|
|
if (request.Amount < 10_000)
|
|
{
|
|
_logger.LogWarning("Amount too low: {Amount}", request.Amount);
|
|
return new PayoutResult
|
|
{
|
|
IsSuccess = false,
|
|
Message = "حداقل مبلغ برداشت 10,000 تومان است",
|
|
ProcessedAt = DateTime.Now
|
|
};
|
|
}
|
|
|
|
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.Now
|
|
};
|
|
}
|
|
|
|
var result = await response.Content.ReadFromJsonAsync<DayaPayoutResponse>(cancellationToken);
|
|
|
|
if (result == null)
|
|
{
|
|
return new PayoutResult
|
|
{
|
|
IsSuccess = false,
|
|
Message = "پاسخ نامعتبر از درگاه",
|
|
ProcessedAt = DateTime.Now
|
|
};
|
|
}
|
|
|
|
_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.Now
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error in ProcessPayoutAsync");
|
|
return new PayoutResult
|
|
{
|
|
IsSuccess = false,
|
|
Message = "خطا در پردازش واریز",
|
|
ProcessedAt = DateTime.Now
|
|
};
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|