elfisa-pharmacy/src/ElectronicPharmacy/Classes/ApiClient.cs
Magomed 800b2971b8 Add API documentation and remove unused single-price endpoint.
Document all client HTTP calls in docs/API.md, link from README, and delete dead GetPriceItem code.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 15:22:13 +03:00

174 lines
6.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Электроннаяармация.Classes
{
public class ApiClient
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
private string _token;
public ApiClient(string baseUrl = null)
{
_baseUrl = (baseUrl ?? AppConfig.ApiBaseUrl).TrimEnd('/');
_httpClient = new HttpClient
{
BaseAddress = new Uri(_baseUrl),
Timeout = TimeSpan.FromSeconds(30)
};
}
/// <summary>
/// Выполняет авторизацию и сохраняет токен
/// </summary>
/// <param name="username">Имя пользователя</param>
/// <param name="password">Пароль</param>
/// <returns>JWT токен</returns>
/// <exception cref="HttpRequestException">При ошибке авторизации</exception>
public async Task<string> LoginAsync(string username, string password)
{
var request = new LoginRequest
{
Username = username,
Password = password
};
try
{
var response = await _httpClient.PostAsJsonAsync("/auth/login", request);
if (response.IsSuccessStatusCode)
{
var loginResponse = await response.Content.ReadFromJsonAsync<LoginResponse>();
_token = loginResponse.Token;
return _token;
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
var error = await response.Content.ReadFromJsonAsync<ErrorResponse>();
throw new UnauthorizedAccessException($"Ошибка авторизации: {error?.Error ?? "Неверные учетные данные"}");
}
else
{
var error = await response.Content.ReadFromJsonAsync<ErrorResponse>();
throw new HttpRequestException($"Ошибка HTTP {response.StatusCode}: {error?.Error ?? "Неизвестная ошибка"}");
}
}
catch (TaskCanceledException)
{
throw new HttpRequestException("Превышено время ожидания ответа сервера");
}
}
/// <summary>
/// Устанавливает токен для последующих запросов
/// </summary>
public void SetToken(string token)
{
_token = token;
}
public string Token => _token;
/// <summary>
/// Проверяет, авторизован ли клиент
/// </summary>
public bool IsAuthenticated => !string.IsNullOrEmpty(_token);
public async Task<PriceSummaryResponse> GetPriceSummaryAsync(string supplierId = null, string regionId = null)
{
if (!IsAuthenticated)
{
throw new InvalidOperationException("Необходимо выполнить авторизацию перед запросом данных");
}
var queryParams = new List<string>();
if (!string.IsNullOrEmpty(supplierId))
{
queryParams.Add($"supplier_id={Uri.EscapeDataString(supplierId)}");
}
if (!string.IsNullOrEmpty(regionId))
{
queryParams.Add($"region_id={Uri.EscapeDataString(regionId)}");
}
var url = "/api/supplier-prices/summary";
if (queryParams.Count > 0)
{
url += "?" + string.Join("&", queryParams);
}
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _token);
try
{
var response = await _httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var summary = await response.Content.ReadFromJsonAsync<PriceSummaryResponse>();
return summary;
}
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
_token = null; // Токен истек или невалиден
var error = await response.Content.ReadFromJsonAsync<ErrorResponse>();
throw new UnauthorizedAccessException($"Сессия истекла: {error?.Error ?? "Необходимо войти заново"}");
}
else
{
var error = await response.Content.ReadFromJsonAsync<ErrorResponse>();
throw new HttpRequestException($"Ошибка HTTP {response.StatusCode}: {error?.Error ?? "Неизвестная ошибка"}");
}
}
catch (TaskCanceledException)
{
throw new HttpRequestException("Превышено время ожидания ответа сервера (таймаут 30 секунд)");
}
}
public async Task<List<InvoiceApiItem>> GetInvoicesAsync()
{
if (!IsAuthenticated)
{
throw new InvalidOperationException("Необходимо выполнить авторизацию перед запросом накладных");
}
_httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _token);
var response = await _httpClient.GetAsync("/api/buyer/invoices");
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(
$"Ошибка загрузки накладных: {(int)response.StatusCode} {response.ReasonPhrase}\n{body}");
}
return JsonSerializer.Deserialize<List<InvoiceApiItem>>(body) ?? new List<InvoiceApiItem>();
}
}
public sealed class InvoiceApiItem
{
public string InvoiceNumber { get; set; }
public string InvoiceDate { get; set; }
public string SupplierName { get; set; }
public string ConsigneeName { get; set; }
public string InvoiceSum { get; set; }
public string RefuseSum { get; set; }
}
}