< Summary

Information
Class: Services.ApiServices.InterpartsEngine.InterpartsEngineResult<T>
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/InterpartsEngine/InterpartsEngineModels.cs
Line coverage
90%
Covered lines: 10
Uncovered lines: 1
Coverable lines: 11
Total lines: 104
Line coverage: 90.9%
Branch coverage
100%
Covered branches: 2
Total branches: 2
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_Status()100%11100%
get_Value()100%11100%
get_ErrorCode()100%11100%
get_Message()100%210%
get_Retry()100%11100%
get_IsOk()100%22100%
Ok(...)100%11100%
NotFound(...)100%11100%
Expired(...)100%11100%
Failure(...)100%11100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/InterpartsEngine/InterpartsEngineModels.cs

#LineLine coverage
 1using System.Text.Json.Serialization;
 2
 3namespace Services.ApiServices.InterpartsEngine;
 4
 5/// <summary>Ответ <c>GET /search/brands?article=…</c>.</summary>
 6public sealed class EngineBrandsResponse
 7{
 8    [JsonPropertyName("article")] public string Article { get; set; } = string.Empty;
 9    [JsonPropertyName("brands")] public List<EngineBrand> Brands { get; set; } = [];
 10}
 11
 12public sealed class EngineBrand
 13{
 14    [JsonPropertyName("brand")] public string Brand { get; set; } = string.Empty;
 15    /// <summary>Название детали, может быть пустым.</summary>
 16    [JsonPropertyName("name")] public string Name { get; set; } = string.Empty;
 17}
 18
 19/// <summary>Ответ <c>GET /search/offers?article=…&amp;brand=…</c>: запрошенная деталь и аналоги вперемешку.</summary>
 20public sealed class EngineOffersResponse
 21{
 22    [JsonPropertyName("article")] public string Article { get; set; } = string.Empty;
 23    [JsonPropertyName("brand")] public string Brand { get; set; } = string.Empty;
 24    [JsonPropertyName("offers")] public List<EngineOffer> Offers { get; set; } = [];
 25
 26    [JsonIgnore] public IEnumerable<EngineOffer> Requested => Offers.Where(o => !o.IsAnalog);
 27    [JsonIgnore] public IEnumerable<EngineOffer> Analogs => Offers.Where(o => o.IsAnalog);
 28
 29    /// <summary>Ближайший срок жизни <c>offer_id</c> в ответе; null — предложений нет.</summary>
 30    [JsonIgnore] public DateTimeOffset? EarliestExpiresAt => Offers.Count == 0 ? null : Offers.Min(o => o.ExpiresAt);
 31}
 32
 33/// <summary>
 34/// Предложение движка. Цена — итоговая для покупателя по тарифу учётки ключа, в копейках; поставщик и
 35/// себестоимость движок не отдаёт. <see cref="OfferId"/> живёт до <see cref="ExpiresAt"/> (~7 минут), хранить его нельз
 36/// </summary>
 37public sealed class EngineOffer
 38{
 39    [JsonPropertyName("offer_id")] public string OfferId { get; set; } = string.Empty;
 40    [JsonPropertyName("article")] public string Article { get; set; } = string.Empty;
 41    /// <summary>Нормализованный артикул (без пробелов и дефисов); в контракте v0.3 его нет.</summary>
 42    [JsonPropertyName("search_code")] public string? SearchCode { get; set; }
 43    [JsonPropertyName("brand")] public string Brand { get; set; } = string.Empty;
 44    [JsonPropertyName("name")] public string Name { get; set; } = string.Empty;
 45    /// <summary><c>requested</c> или <c>analog</c>.</summary>
 46    [JsonPropertyName("match")] public string Match { get; set; } = string.Empty;
 47    [JsonPropertyName("price")] public long PriceKopecks { get; set; }
 48    [JsonPropertyName("currency")] public string Currency { get; set; } = "RUB";
 49    /// <summary>0 — нет в наличии, null — количество неизвестно («наличие уточняется»).</summary>
 50    [JsonPropertyName("quantity_available")] public int? QuantityAvailable { get; set; }
 51    [JsonPropertyName("min_order_qty")] public int MinOrderQty { get; set; } = 1;
 52    /// <summary>null — срок неизвестен («срок уточняется»).</summary>
 53    [JsonPropertyName("delivery_days_min")] public int? DeliveryDaysMin { get; set; }
 54    [JsonPropertyName("delivery_days_max")] public int? DeliveryDaysMax { get; set; }
 55    /// <summary>Подпись вместо поставщика; сейчас всегда пустая.</summary>
 56    [JsonPropertyName("warehouse_label")] public string? WarehouseLabel { get; set; }
 57    [JsonPropertyName("image_url")] public string? ImageUrl { get; set; }
 58    [JsonPropertyName("expires_at")] public DateTimeOffset ExpiresAt { get; set; }
 59
 60    [JsonIgnore] public bool IsAnalog => string.Equals(Match, "analog", StringComparison.OrdinalIgnoreCase);
 61    [JsonIgnore] public decimal PriceRub => PriceKopecks / 100m;
 62    [JsonIgnore] public bool InStock => QuantityAvailable is null or > 0;
 63
 64    public bool IsExpired(DateTimeOffset now) => ExpiresAt <= now;
 65}
 66
 67/// <summary>Формат ошибки движка: <c>{"error":{"code":"…","message":"…","details":{}}}</c>.</summary>
 68internal sealed class EngineErrorEnvelope
 69{
 70    [JsonPropertyName("error")] public EngineErrorBody? Error { get; set; }
 71}
 72
 73internal sealed class EngineErrorBody
 74{
 75    [JsonPropertyName("code")] public string? Code { get; set; }
 76    [JsonPropertyName("message")] public string? Message { get; set; }
 77}
 78
 79public enum InterpartsEngineStatus
 80{
 81    Ok,
 82    /// <summary>Движок такой <c>offer_id</c> не выдавал (404).</summary>
 83    NotFound,
 84    /// <summary>Предложение устарело или исчезло (410) — нужен новый поиск.</summary>
 85    Expired,
 86    Error
 87}
 88
 89/// <summary>Итог запроса к движку без исключений наружу (кроме отмены вызывающим).</summary>
 3190public sealed record InterpartsEngineResult<T>(
 2891    InterpartsEngineStatus Status,
 3292    T? Value = default,
 1793    string? ErrorCode = null,
 094    string? Message = null,
 4095    bool Retry = false)
 96    where T : class
 97{
 1998    public bool IsOk => Status == InterpartsEngineStatus.Ok && Value is not null;
 99
 15100    public static InterpartsEngineResult<T> Ok(T value) => new(InterpartsEngineStatus.Ok, value);
 1101    public static InterpartsEngineResult<T> NotFound(string? message) => new(InterpartsEngineStatus.NotFound, null, "NOT
 1102    public static InterpartsEngineResult<T> Expired(string? message) => new(InterpartsEngineStatus.Expired, null, "OFFER
 14103    public static InterpartsEngineResult<T> Failure(string code, string message, bool retry) => new(InterpartsEngineStat
 104}