< Summary

Information
Class: Services.ApiServices.FavoritPartsApi.FavoritPartsIstraDataManager
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/FavoritPartsApi/FavoritPartsDataManager.cs
Line coverage
100%
Covered lines: 1
Uncovered lines: 0
Coverable lines: 1
Total lines: 109
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

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

#LineLine coverage
 1using System.Globalization;
 2using Newtonsoft.Json;
 3using Newtonsoft.Json.Linq;
 4
 5namespace Services.ApiServices.FavoritPartsApi;
 6
 7/// <summary>Фасад над проценкой (hs/hsprice/) и REST-сервисом (ws/v1/) FavoritParts:
 8/// справочники, реальная серверная корзина, реальные заказы.</summary>
 9public class FavoritPartsDataManager
 10{
 11    private readonly FavoritPartsPriceHttpClient _priceClient;
 12    private readonly FavoritPartsOrderHttpClient _orderClient;
 13
 14    public FavoritPartsDataManager(FavoritPartsPriceHttpClient priceClient, FavoritPartsOrderHttpClient orderClient)
 15    {
 16        _priceClient = priceClient;
 17        _orderClient = orderClient;
 18    }
 19
 20    public Task<JToken> SearchGoodsAsync(string number, string? brand, bool analogues, CancellationToken ct = default) =
 21        _priceClient.SearchAsync(number, brand, analogues, ct);
 22
 23    public Task<JToken> GetStatusesAsync(CancellationToken ct = default) => _orderClient.GetAsync("ws/v1/references/stat
 24
 25    public Task<JToken> GetProfileAsync(CancellationToken ct = default) => _orderClient.GetAsync("ws/v1/references/profi
 26
 27    /// <summary>count=0 удаляет позицию. Количество не суммируется — заменяется последним переданным.
 28    /// Комментарий тоже перезаписывается: вызов без comment очищает его у существующей строки
 29    /// (проверено на боевом API), поэтому при изменении количества комментарий нужно передавать заново.</summary>
 30    public Task<JToken> CartAddAsync(Guid goods, Guid warehouseGroup, decimal count, string? comment, CancellationToken 
 31    {
 32        var query = new Dictionary<string, string?>
 33        {
 34            ["goods"] = FavoritPartsGuid.Format(goods),
 35            ["warehouseGroup"] = FavoritPartsGuid.Format(warehouseGroup),
 36            ["count"] = count.ToString(CultureInfo.InvariantCulture),
 37            ["comment"] = comment
 38        };
 39        return _orderClient.GetAsync("ws/v1/cart/add/", query, ct);
 40    }
 41
 42    public Task<JToken> CartCleanAsync(CancellationToken ct = default) => _orderClient.GetAsync("ws/v1/cart/clean/", ct:
 43
 44    public Task<JToken> GetCartAsync(CancellationToken ct = default) => _orderClient.GetAsync("ws/v1/cart/", ct: ct);
 45
 46    /// <summary>Пары (товар, склад хранения), реально лежащие в корзине поставщика — минимум,
 47    /// которого хватает, чтобы понять, жива ли ещё наша позиция. Корзина серверная: её могли
 48    /// почистить на сайте поставщика или прямым вызовом API, мимо Studio2.</summary>
 49    public async Task<IReadOnlyCollection<(Guid Goods, Guid WarehouseGroup)>> GetCartPositionsAsync(CancellationToken ct
 50    {
 51        var response = await GetCartAsync(ct);
 52        var result = new HashSet<(Guid, Guid)>();
 53        if (response is not JObject obj || obj["cart"] is not JArray cart) return result;
 54
 55        foreach (var row in cart.OfType<JObject>())
 56        {
 57            if (Guid.TryParse(row.Value<string>("goods"), out var goods) &&
 58                Guid.TryParse(row.Value<string>("warehouseGroup"), out var warehouseGroup))
 59            {
 60                result.Add((goods, warehouseGroup));
 61            }
 62        }
 63        return result;
 64    }
 65
 66    /// <summary>Создаёт заказ у поставщика, GoodsList — только позиции одного WarehouseShipping+ShippingDate.
 67    /// Возвращает GUID созданного заказа.</summary>
 68    public async Task<Guid> CreateOrderAsync(FavoritPartsOrderRequest order, CancellationToken ct = default)
 69    {
 70        var json = JsonConvert.SerializeObject(order);
 71        var response = await _orderClient.PostAsync("ws/v1/order/", json, ct);
 72        var raw = response.Type == JTokenType.Array ? response.First?.Value<string>() : response.Value<string>();
 73        if (string.IsNullOrWhiteSpace(raw) || !Guid.TryParse(raw, out var orderId))
 74            throw new FavoritPartsApiException("FavoritParts не вернул GUID созданного заказа.", requestPath: "ws/v1/ord
 75        return orderId;
 76    }
 77
 78    /// <summary>active=1 — только активные заказы; orderIds — точечный отбор; rowsOrder=true — вернуть товарные строки.
 79    public Task<JToken> GetOrdersAsync(bool? active = null, DateOnly? dateStart = null, DateOnly? dateEnd = null,
 80        IReadOnlyCollection<Guid>? orderIds = null, bool rowsOrder = false, CancellationToken ct = default)
 81    {
 82        var query = new List<KeyValuePair<string, string?>>();
 83        if (active == true) query.Add(new("active", "1"));
 84        if (dateStart is not null) query.Add(new("dateStart", dateStart.Value.ToString("yyyyMMdd", CultureInfo.Invariant
 85        if (dateEnd is not null) query.Add(new("dateEnd", dateEnd.Value.ToString("yyyyMMdd", CultureInfo.InvariantCultur
 86        if (rowsOrder) query.Add(new("rowsorder", "1"));
 87        if (orderIds is not null)
 88            foreach (var id in orderIds)
 89                query.Add(new("orderID[]", FavoritPartsGuid.Format(id)));
 90        return _orderClient.GetAsync("ws/v1/order/", query, ct);
 91    }
 92
 93    public Task<JToken> GetOrderAsync(Guid orderId, CancellationToken ct = default) =>
 94        _orderClient.GetAsync($"ws/v1/order/{FavoritPartsGuid.Format(orderId)}/", ct: ct);
 95}
 96
 97/// <summary>Независимый API-клиент аккаунта «Фаворит Истра».</summary>
 98public sealed class FavoritPartsIstraDataManager : FavoritPartsDataManager
 99{
 100    public FavoritPartsIstraDataManager(FavoritPartsPriceHttpClient priceClient, FavoritPartsOrderHttpClient orderClient
 2101        : base(priceClient, orderClient) { }
 102}
 103
 104/// <summary>Независимый API-клиент аккаунта «Фаворит Ростов».</summary>
 105public sealed class FavoritPartsRostovDataManager : FavoritPartsDataManager
 106{
 107    public FavoritPartsRostovDataManager(FavoritPartsPriceHttpClient priceClient, FavoritPartsOrderHttpClient orderClien
 108        : base(priceClient, orderClient) { }
 109}