using CMSMicroservice.Application.DayaLoanCQ.Services; using CMSMicroservice.Domain.Enums; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Json; using System.Threading; using System.Threading.Tasks; using System.Text.Json.Serialization; using System.Linq; namespace CMSMicroservice.Infrastructure.Services; /// /// Mock Implementation برای شبیه‌سازی Daya API /// این کلاس فقط برای تست و توسعه است و باید با Implementation واقعی جایگزین شود /// public class MockDayaLoanApiService : IDayaLoanApiService { private readonly ILogger _logger; public MockDayaLoanApiService(ILogger logger) { _logger = logger; } public async Task> CheckLoanStatusAsync( List nationalCodes, CancellationToken cancellationToken = default) { _logger.LogWarning("⚠️ Using MOCK Daya API Service - Replace with real implementation!"); // شبیه‌سازی تاخیر شبکه await Task.Delay(100, cancellationToken); var results = new List(); foreach (var nationalCode in nationalCodes) { // شبیه‌سازی: کدملی‌هایی که با 1 شروع می‌شوند وام گرفته‌اند if (nationalCode.StartsWith("1")) { results.Add(new DayaLoanStatusResult { NationalCode = nationalCode, Status = DayaLoanStatus.PendingReceive, ContractNumber = $"MOCK-DAYA-{nationalCode}-{DateTime.Now.Ticks}" }); } // شبیه‌سازی: کدملی‌هایی که با 2 شروع می‌شوند رد شده‌اند else if (nationalCode.StartsWith("2")) { results.Add(new DayaLoanStatusResult { NationalCode = nationalCode, Status = DayaLoanStatus.Rejected, ContractNumber = null }); } // بقیه: هنوز بررسی نشده‌اند else { results.Add(new DayaLoanStatusResult { NationalCode = nationalCode, Status = DayaLoanStatus.PendingReceive, ContractNumber = null // هنوز قرارداد صادر نشده }); } } _logger.LogInformation("Mock Daya API returned {Count} results", results.Count); return results; } } /// /// Real Implementation برای API واقعی دایا /// مبتنی بر مستند TA-DAYA-S10-G-MerchantServices /// public class DayaLoanApiService : IDayaLoanApiService { private readonly HttpClient _httpClient; private readonly ILogger _logger; private readonly IConfiguration _configuration; public DayaLoanApiService( HttpClient httpClient, ILogger logger, IConfiguration configuration) { _httpClient = httpClient; _logger = logger; _configuration = configuration; // تنظیم Base Address از Configuration var baseAddress = _configuration["DayaApi:BaseAddress"] ?? "https://testdaya.tadbirandishan.com"; _httpClient.BaseAddress = new Uri(baseAddress); // تنظیم merchant-permission-key از Configuration var permissionKey = _configuration["DayaApi:MerchantPermissionKey"]; if (!string.IsNullOrEmpty(permissionKey)) { _httpClient.DefaultRequestHeaders.Add("merchant-permission-key", permissionKey); } else { _logger.LogWarning("⚠️ DayaApi:MerchantPermissionKey is not configured in appsettings!"); } } public async Task> CheckLoanStatusAsync( List nationalCodes, CancellationToken cancellationToken = default) { try { _logger.LogInformation("Calling Daya API for {Count} national codes", nationalCodes.Count); // ساخت Request Body var requestBody = new DayaContractsRequest { NationalCodes = nationalCodes }; // فراخوانی API var response = await _httpClient.PostAsJsonAsync( "/api/merchant/contracts", requestBody, cancellationToken); // خواندن پاسخ var apiResponse = await response.Content.ReadFromJsonAsync(cancellationToken); // بررسی موفقیت if (apiResponse == null) { _logger.LogError("Daya API returned null response"); return CreateEmptyResults(nationalCodes); } if (!apiResponse.Succeed) { _logger.LogWarning("Daya API call failed. Code: {Code}, Message: {Message}", apiResponse.Code, apiResponse.Message); return CreateEmptyResults(nationalCodes); } if (apiResponse.Data == null || !apiResponse.Data.Any()) { _logger.LogInformation("Daya API returned no contract data"); return CreateEmptyResults(nationalCodes); } // تبدیل نتایج API به مدل داخلی var results = MapApiResponseToResults(apiResponse.Data, nationalCodes); _logger.LogInformation("Daya API returned {Count} contracts for {RequestCount} national codes", results.Count(r => !string.IsNullOrEmpty(r.ContractNumber)), nationalCodes.Count); return results; } catch (HttpRequestException ex) { _logger.LogError(ex, "HTTP error calling Daya API. Status: {StatusCode}", ex.StatusCode); return CreateEmptyResults(nationalCodes); } catch (Exception ex) { _logger.LogError(ex, "Unexpected error calling Daya API"); return CreateEmptyResults(nationalCodes); } } /// /// تبدیل پاسخ API دایا به مدل داخلی /// private List MapApiResponseToResults( List apiData, List requestedNationalCodes) { var results = new List(); // برای هر کد ملی درخواستی foreach (var nationalCode in requestedNationalCodes) { // پیدا کردن آخرین قرارداد این کد ملی (براساس تاریخ) var latestContract = apiData .Where(d => d.NationalCode == nationalCode) .OrderByDescending(d => d.DateTime) .FirstOrDefault(); if (latestContract != null) { // تعیین وضعیت براساس StatusDescription var status = MapStatusDescription(latestContract.StatusDescription); results.Add(new DayaLoanStatusResult { NationalCode = nationalCode, Status = status, ContractNumber = latestContract.ApplicationNo }); _logger.LogDebug("Daya contract found for {NationalCode}: {ContractNo}, Status: {Status}", nationalCode, latestContract.ApplicationNo, latestContract.StatusDescription); } else { // هیچ قراردادی برای این کد ملی پیدا نشد results.Add(new DayaLoanStatusResult { NationalCode = nationalCode, Status = DayaLoanStatus.NotRequested, ContractNumber = null }); } } return results; } /// /// تبدیل StatusDescription دایا به Enum داخلی /// private DayaLoanStatus MapStatusDescription(string statusDescription) { if (string.IsNullOrWhiteSpace(statusDescription)) return DayaLoanStatus.NotRequested; // براساس مستند دایا: "فعال شده (در انتظار تسویه)" = وام تایید شده if (statusDescription.Contains("فعال شده") || statusDescription.Contains("در انتظار تسویه")) return DayaLoanStatus.PendingReceive; if (statusDescription.Contains("رد شده") || statusDescription.Contains("رد")) return DayaLoanStatus.Rejected; if (statusDescription.Contains("بررسی") || statusDescription.Contains("در حال")) return DayaLoanStatus.UnderReview; // پیش‌فرض return DayaLoanStatus.NotRequested; } /// /// ساخت نتایج خالی در صورت خطا /// private List CreateEmptyResults(List nationalCodes) { return nationalCodes.Select(nc => new DayaLoanStatusResult { NationalCode = nc, Status = DayaLoanStatus.NotRequested, ContractNumber = null }).ToList(); } } #region Daya API Models /// /// Request body برای /api/merchant/contracts /// internal class DayaContractsRequest { [JsonPropertyName("NationalCodes")] public List NationalCodes { get; set; } = new(); } /// /// Response از /api/merchant/contracts /// internal class DayaContractsResponse { [JsonPropertyName("succeed")] public bool Succeed { get; set; } [JsonPropertyName("code")] public int Code { get; set; } [JsonPropertyName("message")] public string? Message { get; set; } [JsonPropertyName("data")] public List? Data { get; set; } } /// /// داده‌های قرارداد در پاسخ API /// internal class DayaContractData { [JsonPropertyName("nationalCode")] public string NationalCode { get; set; } = string.Empty; [JsonPropertyName("applicationNo")] public string ApplicationNo { get; set; } = string.Empty; [JsonPropertyName("statusDescription")] public string StatusDescription { get; set; } = string.Empty; [JsonPropertyName("dateTime")] public DateTime DateTime { get; set; } } #endregion