< Summary

Information
Class: Services.SupplierStatusServices.Providers.BergSupplierStatusProvider
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/SupplierStatusServices/Providers/BergSupplierStatusProvider.cs
Line coverage
100%
Covered lines: 49
Uncovered lines: 0
Coverable lines: 49
Total lines: 98
Line coverage: 100%
Branch coverage
100%
Covered branches: 18
Total branches: 18
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_ProviderKey()100%11100%
FetchCartAsync(...)100%11100%
FetchOrderAsync()100%2222100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/SupplierStatusServices/Providers/BergSupplierStatusProvider.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using OzonDomains.Models;
 3using OzonDomains.Models.SupplierStatuses;
 4using OzonRepositories.Context;
 5using Services.ApiServices.BergApi;
 6
 7namespace Services.SupplierStatusServices.Providers;
 8
 9/// <summary>
 10/// Статусы Berg. Корзина у Berg локальная, поэтому её стадия читается из BergCartItems, а статусы
 11/// оформленных заказов — из ordering/states.json по сохранённым идентификаторам. Статус у Berg
 12/// живёт на строке заказа, а не на заказе: сопоставление идёт через BergOrderItems.
 13/// </summary>
 14public sealed class BergSupplierStatusProvider : ISupplierStatusProvider
 15{
 16    private readonly ApplicationDbContext _db;
 17    private readonly BergDataManager _berg;
 18    private readonly LocalCartStatusReader _localCart;
 19
 3220    public BergSupplierStatusProvider(ApplicationDbContext db, BergDataManager berg, LocalCartStatusReader localCart)
 21    {
 3222        _db = db;
 3223        _berg = berg;
 3224        _localCart = localCart;
 3225    }
 26
 927    public string ProviderKey => ApiSupplierSettings.BergProviderKey;
 28
 29    public Task<IReadOnlyList<SupplierStatusSnapshot>> FetchCartAsync(IReadOnlyList<OrderSupplierStateRef> states,
 730        CancellationToken ct) => _localCart.ReadAsync(ProviderKey, states, ct);
 31
 32    public async Task<IReadOnlyList<SupplierStatusSnapshot>> FetchOrderAsync(IReadOnlyList<OrderSupplierStateRef> states
 33        CancellationToken ct)
 34    {
 2535        if (states.Count == 0) return [];
 36
 5137        var orderIds = states.Select(x => x.OrderId).Distinct().ToList();
 2338        var lines = await _db.BergOrderItems.AsNoTracking()
 2339            .Where(x => orderIds.Contains(x.StudioOrderId))
 2340            .Select(x => new { x.StudioOrderId, x.Sequence, x.BergOrder!.ExternalOrderId, x.BergOrder.CreatedAtUtc })
 2341            .ToListAsync(ct);
 2442        if (lines.Count == 0) return [];
 43
 44        // Одна строка Studio2 может попасть в несколько заказов Berg (повторное оформление);
 45        // актуален последний.
 2246        var latest = lines
 2547            .GroupBy(x => x.StudioOrderId)
 9548            .ToDictionary(g => g.Key, g => g.OrderByDescending(x => x.CreatedAtUtc).First());
 49
 4650        var externalIds = latest.Values.Select(x => x.ExternalOrderId.ToString()).Distinct().ToList();
 51
 52        IReadOnlyList<BergOrderState> orders;
 53        try
 54        {
 2255            var response = await _berg.GetStatesAsync(externalIds, ct);
 1756            orders = BergDataManager.ParseOrders(response);
 1757        }
 558        catch (Exception ex) when (ex is BergApiException or HttpRequestException or TaskCanceledException)
 59        {
 1160            return states.Select(x => new SupplierStatusSnapshot
 1161            {
 1162                OrderId = x.OrderId, Kind = SupplierStatusKind.Order, StatusName = string.Empty,
 1163                Error = $"Berg: {ex.Message}"
 1164            }).ToList();
 65        }
 66
 3667        var byExternalId = orders.ToDictionary(x => x.Id);
 1768        var result = new List<SupplierStatusSnapshot>();
 7469        foreach (var state in states)
 70        {
 2071            if (!latest.TryGetValue(state.OrderId, out var link) ||
 2072                !byExternalId.TryGetValue(link.ExternalOrderId, out var order))
 73                continue;
 74
 75            // Berg нумерует строки sequence; если номер не сохранился, заказ односточный —
 76            // берём единственную строку.
 3877            var line = order.Items.FirstOrDefault(x => x.Sequence == link.Sequence)
 1878                       ?? (order.Items.Count == 1 ? order.Items[0] : null);
 1879            if (line?.StateId is null)
 80                continue;
 81
 1682            result.Add(new SupplierStatusSnapshot
 1683            {
 1684                OrderId = state.OrderId,
 1685                Kind = SupplierStatusKind.Order,
 1686                ExternalCode = line.StateId.Value.ToString(),
 1687                StatusName = string.IsNullOrWhiteSpace(line.StateName) ? $"Статус {line.StateId}" : line.StateName!,
 1688                ExternalOrderNumber = order.Id.ToString(),
 1689                ExternalOrderId = order.Id.ToString(),
 1690                ExternalLineId = line.Sequence.ToString(),
 1691                QuantityConfirmed = line.Quantity,
 1692                ExpectedDeliveryAt = line.AssuredTime ?? line.AverageTime
 1693            });
 94        }
 95
 1796        return result;
 2497    }
 98}