< Summary

Information
Class: Services.ApiServices.FavoritPartsApi.FavoritPartsPriceHttpClient
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/FavoritPartsApi/FavoritPartsPriceHttpClient.cs
Line coverage
19%
Covered lines: 8
Uncovered lines: 33
Coverable lines: 41
Total lines: 82
Line coverage: 19.5%
Branch coverage
0%
Covered branches: 0
Total branches: 16
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
SearchAsync()0%272160%
BuildUri(...)100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/FavoritPartsApi/FavoritPartsPriceHttpClient.cs

#LineLine coverage
 1using Microsoft.Extensions.Options;
 2using Newtonsoft.Json.Linq;
 3using Services.ApiServices.ApiSupplierRequestLog;
 4
 5namespace Services.ApiServices.FavoritPartsApi;
 6
 7/// <summary>Клиент легаси 1С HS-сервиса проценки FavoritParts (hs/hsprice/).
 8/// Отдельный хост/путь от REST-сервиса корзины/заказов (ws/v1/), авторизация — query-параметры key
 9/// и developerKey (документация проценки от 06.03.2023 знает только key, но требование ключа
 10/// разработчика из документации заказов распространяется на сервис целиком, а лишний параметр
 11/// проценка игнорирует). Ошибки — {"error": "..."} в теле при HTTP 200.</summary>
 12public class FavoritPartsPriceHttpClient
 13{
 14    private const string ProviderKey = "FavoritParts";
 15    private readonly IHttpClientFactory _factory;
 16    private readonly IOptionsMonitor<FavoritPartsConfig> _config;
 17    private readonly ApiSupplierRequestLogStore _logs;
 18    private readonly string _providerKey;
 19    private readonly string _optionsName;
 20
 3421    public FavoritPartsPriceHttpClient(IHttpClientFactory factory, IOptionsMonitor<FavoritPartsConfig> config, ApiSuppli
 3422        string providerKey = "FavoritParts", string optionsName = "")
 23    {
 3424        _factory = factory;
 3425        _config = config;
 3426        _logs = logs;
 3427        _providerKey = providerKey;
 3428        _optionsName = optionsName;
 3429    }
 30
 31    public async Task<JToken> SearchAsync(string number, string? brand, bool analogues, CancellationToken ct = default)
 32    {
 033        var config = string.IsNullOrEmpty(_optionsName) ? _config.CurrentValue : _config.Get(_optionsName);
 034        if (string.IsNullOrWhiteSpace(config.ClientKey))
 035            throw new FavoritPartsApiException("Не настроен FavoritParts:ClientKey.");
 36
 037        var query = new Dictionary<string, string?>
 038        {
 039            ["key"] = config.ClientKey,
 040            ["developerKey"] = config.DeveloperKey,
 041            ["number"] = number,
 042            ["brand"] = brand,
 043            ["analogues"] = analogues ? "on" : null,
 044            ["info"] = "on"
 045        };
 046        var uri = BuildUri(config, "hs/hsprice/", query);
 47
 048        var timer = System.Diagnostics.Stopwatch.StartNew();
 49        try
 50        {
 051            using var response = await _factory.CreateClient("FavoritPartsPriceApi").GetAsync(uri, ct);
 052            var text = await response.Content.ReadAsStringAsync(ct);
 053            _logs.Add(_providerKey, HttpMethod.Get.Method, "hs/hsprice/", (int)response.StatusCode, timer, uri.Query, te
 54
 055            if (!response.IsSuccessStatusCode)
 056                throw new FavoritPartsApiException($"FavoritParts (проценка) вернул HTTP {(int)response.StatusCode}.", (
 57
 58            JToken token;
 059            try { token = JToken.Parse(text); }
 060            catch (Exception ex) { throw new FavoritPartsApiException("FavoritParts (проценка) вернул невалидный JSON.",
 61
 062            if (token is JObject obj && obj["error"] is { Type: JTokenType.String } errorToken)
 063                throw new FavoritPartsApiException(errorToken.Value<string>() ?? "FavoritParts (проценка) вернул ошибку.
 64
 065            return token;
 66        }
 067        catch (FavoritPartsApiException) { throw; }
 068        catch (Exception ex)
 69        {
 070            _logs.Add(_providerKey, HttpMethod.Get.Method, "hs/hsprice/", null, timer, uri.Query, ex.Message);
 071            throw new FavoritPartsApiException("Не удалось выполнить запрос к FavoritParts (проценка).", requestPath: "h
 72        }
 073    }
 74
 75    private static Uri BuildUri(FavoritPartsConfig config, string path, IReadOnlyDictionary<string, string?> query)
 76    {
 077        var builder = new UriBuilder(config.BaseUrl.TrimEnd('/') + "/" + path.TrimStart('/'));
 078        builder.Query = string.Join("&", query.Where(x => !string.IsNullOrWhiteSpace(x.Value))
 079            .Select(x => $"{Uri.EscapeDataString(x.Key)}={Uri.EscapeDataString(x.Value!)}"));
 080        return builder.Uri;
 81    }
 82}