< Summary

Information
Class: OzonOrdersWeb.TransactionServices.FavoritPartsOrderLookup
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Services/Transactions/SupplierOrderLookups.cs
Line coverage
45%
Covered lines: 18
Uncovered lines: 22
Coverable lines: 40
Total lines: 150
Line coverage: 45%
Branch coverage
76%
Covered branches: 20
Total branches: 26
Branch coverage: 76.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
get_ProviderKeys()100%210%
FindAsync()0%2040%
Scan(...)92.85%1414100%
OrderNumber(...)87.5%9880%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Services/Transactions/SupplierOrderLookups.cs

#LineLine coverage
 1using System.Globalization;
 2using Microsoft.EntityFrameworkCore;
 3using Newtonsoft.Json.Linq;
 4using OzonDomains.Models;
 5using OzonRepositories.Context;
 6using Services.ApiServices.ArmtekApi;
 7using Services.ApiServices.FavoritPartsApi;
 8using Services.SupplierStatusServices;
 9
 10namespace OzonOrdersWeb.TransactionServices;
 11
 12/// <summary>
 13/// Сверка заказов Armtek: отчёт <c>getOrderReportByDate</c> по каждому клиенту (KUNRG) с даты начала отправки;
 14/// заказ узнаётся по метке Studio2 в комментарии заказа (<c>TEXT_ORD</c> → поле <c>COMMENT</c> отчёта).
 15/// Только чтение. «Не найден» возвращается лишь когда метка заведомо читается — в отчёте есть хотя бы один заказ
 16/// с меткой Studio2; иначе отсутствие метки ничего не доказывает и сверка считается недоступной.
 17/// </summary>
 18public sealed class ArmtekOrderLookup : ISupplierOrderLookup
 19{
 20    private readonly ApplicationDbContext _db;
 21    private readonly ArmtekDataManager _armtek;
 22    private readonly ArmtekByDataManager _armtekBy;
 23
 24    public ArmtekOrderLookup(ApplicationDbContext db, ArmtekDataManager armtek, ArmtekByDataManager armtekBy)
 25    {
 26        _db = db;
 27        _armtek = armtek;
 28        _armtekBy = armtekBy;
 29    }
 30
 31    public IReadOnlyCollection<string> ProviderKeys { get; } = [ApiSupplierSettings.ArmtekProviderKey, ApiSupplierSettin
 32
 33    public async Task<SupplierOrderLookupResult> FindAsync(SupplierOrderLookupRequest request, CancellationToken ct)
 34    {
 35        var isBy = string.Equals(request.ProviderKey, ApiSupplierSettings.ArmtekByProviderKey, StringComparison.OrdinalI
 36        var client = isBy ? (ArmtekDataManager)_armtekBy : _armtek;
 37        var vkorg = isBy ? "2000" : "4000";
 38        var providerKey = isBy ? ApiSupplierSettings.ArmtekByProviderKey : ApiSupplierSettings.ArmtekProviderKey;
 39
 40        var buyers = (await _db.ArmtekDeliveryAddressMappings.AsNoTracking()
 41                .Where(x => x.ProviderKey == providerKey).Select(x => x.BuyerKunnr).ToListAsync(ct))
 42            .Concat(await _db.ArmtekOrders.AsNoTracking()
 43                .Where(x => x.ProviderKey == providerKey).Select(x => x.Kunrg).Distinct().ToListAsync(ct))
 44            .Where(x => !string.IsNullOrWhiteSpace(x))
 45            .Distinct(StringComparer.Ordinal)
 46            .ToList();
 47        if (buyers.Count == 0)
 48            return SupplierOrderLookupResult.Unavailable("Не найден клиент Армтек (KUNRG) для сверки.");
 49
 50        var from = request.IntentCreatedUtc.Date.AddDays(-1);
 51        var to = DateTime.UtcNow.Date.AddDays(1);
 52        var labelVisible = false;
 53        foreach (var buyer in buyers)
 54        {
 55            var response = await client.GetOrderReportByDateAsync(buyer, vkorg, createdFrom: from, createdTo: to,
 56                includeSales: true, currentLoginOnly: true, ct: ct);
 57            if (response.HasErrors)
 58                return SupplierOrderLookupResult.Unavailable("Армтек не отдал отчёт по заказам: " +
 59                    string.Join("; ", response.Messages.Where(m => m.Type is "E" or "A").Select(m => m.Text)));
 60
 61            foreach (var item in response.Resp?.Data ?? [])
 62            {
 63                labelVisible |= StudioOrderCommentLink.IsStudioComment(item.Comment);
 64                if (StudioOrderCommentLink.ExtractOrderIds(item.Comment).Contains(request.StudioOrderId))
 65                    return new SupplierOrderLookupResult(SupplierOrderLookupStatus.Found, item.Order, "Найден по метке S
 66            }
 67        }
 68
 69        return labelVisible
 70            ? new SupplierOrderLookupResult(SupplierOrderLookupStatus.NotFound, null, "Заказа с меткой Studio2 в отчёте 
 71            : SupplierOrderLookupResult.Unavailable("В отчёте Армтек нет ни одного заказа с меткой Studio2 за период — м
 72    }
 73}
 74
 75/// <summary>
 76/// Сверка заказов FavoritParts (три аккаунта): <c>GET ws/v1/order/</c> с датой начала отправки и строками заказа;
 77/// ищет в ответе комментарий с меткой Studio2 (<see cref="StudioOrderCommentLink"/>). Только чтение.
 78/// Как и у Armtek, «не найден» возвращается лишь когда метки Studio2 в ответе заведомо читаются.
 79/// </summary>
 80public sealed class FavoritPartsOrderLookup : ISupplierOrderLookup
 81{
 82    private readonly FavoritPartsDataManager _favoritParts;
 83    private readonly FavoritPartsIstraDataManager _istra;
 84    private readonly FavoritPartsRostovDataManager _rostov;
 85
 086    public FavoritPartsOrderLookup(FavoritPartsDataManager favoritParts, FavoritPartsIstraDataManager istra, FavoritPart
 87    {
 088        _favoritParts = favoritParts;
 089        _istra = istra;
 090        _rostov = rostov;
 091    }
 92
 093    public IReadOnlyCollection<string> ProviderKeys { get; } =
 094    [
 095        ApiSupplierSettings.FavoritPartsProviderKey, ApiSupplierSettings.FavoritPartsIstraProviderKey, ApiSupplierSettin
 096    ];
 97
 98    public async Task<SupplierOrderLookupResult> FindAsync(SupplierOrderLookupRequest request, CancellationToken ct)
 99    {
 0100        FavoritPartsDataManager manager = request.ProviderKey switch
 0101        {
 0102            ApiSupplierSettings.FavoritPartsIstraProviderKey => _istra,
 0103            ApiSupplierSettings.FavoritPartsRostovProviderKey => _rostov,
 0104            _ => _favoritParts
 0105        };
 106
 0107        var payload = await manager.GetOrdersAsync(
 0108            dateStart: DateOnly.FromDateTime(request.IntentCreatedUtc.AddDays(-1)),
 0109            dateEnd: DateOnly.FromDateTime(DateTime.UtcNow.AddDays(1)),
 0110            rowsOrder: true, ct: ct);
 0111        return Scan(payload, request.StudioOrderId);
 0112    }
 113
 114    /// <summary>Обход ответа: комментарий с нашей меткой и номер ближайшего родительского заказа.</summary>
 115    public static SupplierOrderLookupResult Scan(JToken payload, int studioOrderId)
 116    {
 4117        var labelVisible = false;
 23118        foreach (var node in payload.SelectTokens("$..*").OfType<JObject>())
 119        {
 8120            var comment = node.Properties()
 24121                .FirstOrDefault(x => string.Equals(x.Name, "comment", StringComparison.OrdinalIgnoreCase))?.Value as JVa
 8122            var text = comment?.Value?.ToString();
 8123            if (string.IsNullOrWhiteSpace(text)) continue;
 124
 4125            labelVisible |= StudioOrderCommentLink.IsStudioComment(text);
 4126            if (!StudioOrderCommentLink.ExtractOrderIds(text).Contains(studioOrderId)) continue;
 127
 1128            var number = OrderNumber(node);
 1129            return new SupplierOrderLookupResult(SupplierOrderLookupStatus.Found, number, "Найден по метке Studio2 в ком
 130        }
 131
 3132        return labelVisible
 3133            ? new SupplierOrderLookupResult(SupplierOrderLookupStatus.NotFound, null, "Заказа с меткой Studio2 в ответе 
 3134            : SupplierOrderLookupResult.Unavailable("В ответе FavoritParts нет ни одного комментария с меткой Studio2 за
 1135    }
 136
 137    private static string? OrderNumber(JToken node)
 138    {
 8139        for (var current = node; current is not null; current = current.Parent)
 140        {
 4141            if (current is JObject obj)
 142            {
 2143                var number = obj["number"]?.ToString();
 3144                if (!string.IsNullOrWhiteSpace(number)) return number;
 145            }
 146        }
 147
 0148        return null;
 149    }
 150}