< Summary

Information
Class: Services.BitrixStockServices.BitrixStockSyncReportRowPresenter
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/BitrixStockServices/BitrixStockSyncReportRowPresenter.cs
Line coverage
87%
Covered lines: 99
Uncovered lines: 14
Coverable lines: 113
Total lines: 174
Line coverage: 87.6%
Branch coverage
73%
Covered branches: 123
Total branches: 168
Branch coverage: 73.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
GetSkipLabel(...)100%3030100%
GetTargetQty(...)100%1212100%
FormatDeltaC0(...)100%88100%
DeltaC0CssClass(...)100%88100%
FormatOzonApplyStatus(...)76.47%343493.1%
FormatOzonCleanupStatus(...)13.63%1472236.36%
FormatDeltaItog(...)91.66%1212100%
FormatPriceIndex(...)50%5466.66%
PriceIndexCssClass(...)0%2040%
FormatPushedNew(...)59.09%222290%
PushedNewCssClass(...)83.33%1212100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/BitrixStockServices/BitrixStockSyncReportRowPresenter.cs

#LineLine coverage
 1namespace Services.BitrixStockServices;
 2
 3/// <summary>Форматирование ячеек строк отчёта BitrixStock (Excel + HTML).</summary>
 4public static class BitrixStockSyncReportRowPresenter
 5{
 16    public static readonly Dictionary<string, (string BgHex, string FgHex, string Label)> IndexStyles =
 17        new(StringComparer.OrdinalIgnoreCase)
 18        {
 19            ["SUPER"]         = ("#EDE9FE", "#7C3AED", "Супервыгодный"),
 110            ["GREEN"]         = ("#D1E7DD", "#0A3C22", "Выгодный"),
 111            ["YELLOW"]        = ("#FFF3CD", "#664200", "Умеренный"),
 112            ["RED"]           = ("#F8D7DA", "#841F27", "Невыгодный"),
 113            ["WITHOUT_INDEX"] = ("#E9ECEF", "#6C757D", "Нет индекса"),
 114            ["BENEFIT"]       = ("#D1E7DD", "#0A3C22", "Выгодный"),
 115            ["AVERAGE"]       = ("#FFF3CD", "#664200", "Умеренный"),
 116            ["OVERPRICED"]    = ("#F8D7DA", "#841F27", "Невыгодный"),
 117        };
 18
 19    public static string GetSkipLabel(string? error)
 20    {
 3321        if (string.IsNullOrEmpty(error)) return "Пропущено";
 2922        if (error.Contains("Не найден", StringComparison.OrdinalIgnoreCase) ||
 2923            error.Contains("product_id", StringComparison.OrdinalIgnoreCase) ||
 3424            error.Contains("склада Ozon", StringComparison.OrdinalIgnoreCase)) return "Не участвовал в обработке";
 2725        if (error.Contains("совпадает", StringComparison.OrdinalIgnoreCase)) return "Уже совпадает";
 2126        if (error.StartsWith("К2", StringComparison.OrdinalIgnoreCase) &&
 2527            error.Contains("приоритет", StringComparison.OrdinalIgnoreCase)) return "⓪ К2 обнулено (К1)";
 1728        if (error.StartsWith("К1", StringComparison.OrdinalIgnoreCase) &&
 2029            error.Contains("приоритет", StringComparison.OrdinalIgnoreCase)) return "К1 → К2 обнулён";
 1430        if (error.Contains("связь отключена", StringComparison.OrdinalIgnoreCase) ||
 1931            error.Contains("обнулено", StringComparison.OrdinalIgnoreCase)) return "⓪₂ Обнулено (связь)";
 1132        if (error.Contains("К1 не продается", StringComparison.OrdinalIgnoreCase)) return "К2: К1 не продается";
 1033        if (error.Contains("архив", StringComparison.OrdinalIgnoreCase)) return "Архивный товар";
 634        if (error.Contains("уже 0", StringComparison.OrdinalIgnoreCase)) return "Уже 0";
 335        if (error.StartsWith("К2 пропущен: ", StringComparison.OrdinalIgnoreCase)) return error;
 136        return $"Пропущено: {error}";
 37    }
 38
 17339    public static int? GetTargetQty(BitrixStockSyncReportWarehouseLineDto w) => w.Action switch
 17340    {
 241        BitrixStockSyncReportActions.Clear         => 0,
 342        BitrixStockSyncReportActions.ClearDisabledLink => 0,
 16243        BitrixStockSyncReportActions.Push          => w.OneCQty,
 144        BitrixStockSyncReportActions.Decrease      => w.OneCQty,
 145        BitrixStockSyncReportActions.FbsNoWarehouse => w.OneCQty,
 146        BitrixStockSyncReportActions.CleanupExtra   => 0,
 347        _                                          => null
 17348    };
 49
 50    public static string FormatDeltaC0(decimal? oneCPrice, decimal? prevOneCPrice)
 51    {
 13752        if (!oneCPrice.HasValue || !prevOneCPrice.HasValue) return "";
 753        var diff = (long)Math.Round(oneCPrice.Value) - (long)Math.Round(prevOneCPrice.Value);
 754        var prevFmt = ((long)Math.Round(prevOneCPrice.Value)).ToString("N0");
 955        if (diff == 0) return "=";
 556        return diff > 0 ? $"↑ +{diff:N0} (было {prevFmt})" : $"↓ {diff:N0} (было {prevFmt})";
 57    }
 58
 59    public static string DeltaC0CssClass(decimal? oneCPrice, decimal? prevOneCPrice)
 60    {
 12761        if (!oneCPrice.HasValue || !prevOneCPrice.HasValue) return "";
 362        var diff = (long)Math.Round(oneCPrice.Value) - (long)Math.Round(prevOneCPrice.Value);
 463        if (diff == 0) return "text-muted";
 264        return diff > 0 ? "text-success" : "text-danger";
 65    }
 66
 67    public static string FormatOzonApplyStatus(BitrixStockSyncReportWarehouseLineDto w)
 68    {
 21969        if (string.Equals(w.Action, BitrixStockSyncReportActions.ClearDisabledLink, StringComparison.OrdinalIgnoreCase))
 70        {
 471            return w.OzonApplyStatus switch
 472            {
 373                "Success" => $"⓪₂ Связь снята | {w.OzonWarehouseName}",
 174                "Failed" => $"✗ {w.OzonApplyError}",
 075                _ => "⓪₂ Связь снята"
 476            };
 77        }
 78
 79        // Строки этапа 5: OzonApplyStatus у них всегда NULL, поэтому колонка «Статус Ozon»
 80        // оставалась пустой и провалившееся обнуление сироты выглядело как «ничего не произошло».
 21581        if (w.IsOzonOrphan)
 82        {
 483            return w.OzonOrphanStatus switch
 484            {
 285                "Success" => "✓ Обнулено (сирота)",
 286                "Failed" => "✗ Не обнулено — см. примечание",
 087                _ => ""
 488            };
 89        }
 90
 21191        return w.OzonApplyStatus switch
 21192        {
 15593            "Success" when !string.IsNullOrEmpty(w.OzonApplyError) => GetSkipLabel(w.OzonApplyError),
 15594            "Success" => "✓ Применено",
 295            "Failed" when (w.OzonApplyError ?? "").Contains("Не продается", StringComparison.OrdinalIgnoreCase)
 196                => "⊘ Не продается",
 197            "Failed" => $"✗ Ошибка: {w.OzonApplyError}",
 198            "Pending" => "Ожидает",
 199            "Skipped" => GetSkipLabel(w.OzonApplyError),
 52100            _ => w.Action is BitrixStockSyncReportActions.NotFound
 52101                     or BitrixStockSyncReportActions.FbsNoWarehouse
 52102                     or BitrixStockSyncReportActions.NotForSale
 52103                ? "Не участвовал в обработке"
 52104                : ""
 211105        };
 106    }
 107
 108    public static string FormatOzonCleanupStatus(BitrixStockSyncReportWarehouseLineDto w)
 109    {
 101110        return w.OzonCleanupStatus switch
 101111        {
 0112            "Success" when (w.OzonCleanupError ?? "").Contains("Сохранён", StringComparison.OrdinalIgnoreCase) => "✓ Сох
 0113            "Success" when (w.OzonCleanupError ?? "").Contains("⓪₃", StringComparison.OrdinalIgnoreCase) => "⓪₃ Этап 3: 
 0114            "Success" when w.Action == BitrixStockSyncReportActions.CleanupExtra => "⓪₃ Этап 3: обнулён",
 0115            "Success" when (w.OzonCleanupError ?? "").Contains("Обнулён", StringComparison.OrdinalIgnoreCase) => "⓪ Обну
 0116            "Success" => "✓",
 0117            "Failed" => $"✗ {w.OzonCleanupError}",
 0118            "Skipped" => w.OzonCleanupError ?? "пропуск",
 101119            _ => ""
 101120        };
 121    }
 122
 123    public static string FormatDeltaItog(BitrixStockSyncReportWarehouseLineDto w, out string cssClass)
 124    {
 131125        cssClass = "text-muted";
 131126        if (w.OzonQtyAfter.HasValue)
 127        {
 9128            var actualDelta = w.OzonQtyAfter.Value - w.OzonQty;
 9129            cssClass = actualDelta > 0 ? "text-success fw-bold" : actualDelta < 0 ? "text-danger fw-bold" : "text-muted 
 9130            return actualDelta > 0 ? $"+{actualDelta}" : actualDelta.ToString();
 131        }
 122132        return w.Delta > 0 ? $"+{w.Delta}" : w.Delta == 0 ? "0" : w.Delta.ToString();
 133    }
 134
 135    public static string FormatPriceIndex(string? colorIndex)
 136    {
 3137        if (string.IsNullOrEmpty(colorIndex) || !IndexStyles.TryGetValue(colorIndex, out var s))
 0138            return "";
 3139        return s.Label;
 140    }
 141
 142    public static string PriceIndexCssClass(string? colorIndex)
 143    {
 0144        if (string.IsNullOrEmpty(colorIndex)) return "";
 0145        var key = colorIndex.ToUpperInvariant();
 0146        return IndexStyles.ContainsKey(key) ? $"bsx-price-index-{key}" : "";
 147    }
 148
 149    public static string FormatPushedNew(OzonPriceInfoDto? pi)
 150    {
 3151        if (pi?.PricePushedNew is { } pn)
 1152            return ((long)Math.Round(pn)).ToString("N0");
 2153        if (pi?.PricePushStatus == "Unchanged")
 154        {
 1155            var cur = pi.SellingPrice ?? pi.TruePrice;
 1156            return cur.HasValue ? $"без изменений · {(long)Math.Round(cur.Value):N0}" : "без изменений";
 157        }
 1158        if (pi?.PricePushStatus == "Error")
 159        {
 1160            var cur = pi.SellingPrice ?? pi.TruePrice;
 1161            var err = string.IsNullOrEmpty(pi.PricePushError) ? "Ошибка" : $"Ошибка: {pi.PricePushError}";
 1162            return cur.HasValue ? $"{err} · {(long)Math.Round(cur.Value):N0}" : err;
 163        }
 0164        return "";
 165    }
 166
 167    public static string PushedNewCssClass(OzonPriceInfoDto? pi)
 168    {
 8169        if (pi?.PricePushedNew.HasValue == true) return "text-success fw-bold";
 5170        if (pi?.PricePushStatus == "Error") return "text-danger";
 4171        if (pi?.PricePushStatus == "Unchanged") return "text-muted fst-italic";
 2172        return "";
 173    }
 174}