< Summary

Information
Class: OzonOrdersWeb.Areas.Studio2.AnalysisServices.ForecastDtoMapper
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/AnalysisServices/ForecastDtoMapper.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 93
Coverable lines: 93
Total lines: 118
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 37
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
DayOfWeekName(...)0%7280%
DirectionName(...)0%4260%
TrendDescription(...)0%110100%
PriorityName(...)0%3050%
AbcDescription(...)0%2040%
XyzDescription(...)0%2040%
Trend(...)100%210%
Build(...)100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/AnalysisServices/ForecastDtoMapper.cs

#LineLine coverage
 1using OzonOrdersWeb.Areas.Studio2.DTOs;
 2
 3namespace OzonOrdersWeb.Areas.Studio2.AnalysisServices;
 4
 5/// <summary>Русские подписи и DTO для вкладки «Прогнозирование и тренды».</summary>
 6public static class ForecastDtoMapper
 7{
 08    public static string DayOfWeekName(DayOfWeek day) => day switch
 09    {
 010        DayOfWeek.Monday => "Понедельник",
 011        DayOfWeek.Tuesday => "Вторник",
 012        DayOfWeek.Wednesday => "Среда",
 013        DayOfWeek.Thursday => "Четверг",
 014        DayOfWeek.Friday => "Пятница",
 015        DayOfWeek.Saturday => "Суббота",
 016        DayOfWeek.Sunday => "Воскресенье",
 017        _ => day.ToString()
 018    };
 19
 020    public static string DirectionName(TrendAnalysisService.TrendDirection direction) => direction switch
 021    {
 022        TrendAnalysisService.TrendDirection.StrongGrowth => "Сильный рост",
 023        TrendAnalysisService.TrendDirection.ModerateGrowth => "Умеренный рост",
 024        TrendAnalysisService.TrendDirection.Stable => "Стабильно",
 025        TrendAnalysisService.TrendDirection.ModerateDecline => "Умеренное снижение",
 026        TrendAnalysisService.TrendDirection.StrongDecline => "Сильное снижение",
 027        _ => "Неизвестно"
 028    };
 29
 30    public static string TrendDescription(TrendAnalysisService.TrendResult trend)
 31    {
 032        var direction = trend.Direction switch
 033        {
 034            TrendAnalysisService.TrendDirection.StrongGrowth => "сильный рост",
 035            TrendAnalysisService.TrendDirection.ModerateGrowth => "умеренный рост",
 036            TrendAnalysisService.TrendDirection.Stable => "стабильность",
 037            TrendAnalysisService.TrendDirection.ModerateDecline => "умеренное снижение",
 038            TrendAnalysisService.TrendDirection.StrongDecline => "сильное снижение",
 039            _ => "неопределенный тренд"
 040        };
 41
 042        return $"Наблюдается {direction} ({trend.GrowthPercentage:F1}% за период). " +
 043               $"Коэффициент детерминации R² = {trend.R2:F3} " +
 044               $"(качество модели: {(trend.R2 > 0.7 ? "высокое" : trend.R2 > 0.4 ? "среднее" : "низкое")}). " +
 045               $"Анализ основан на {trend.DataPointsCount} точках данных.";
 46    }
 47
 048    public static string PriorityName(PurchaseRecommendationService.RecommendationPriority priority) => priority switch
 049    {
 050        PurchaseRecommendationService.RecommendationPriority.Critical => "Критический",
 051        PurchaseRecommendationService.RecommendationPriority.High => "Высокий",
 052        PurchaseRecommendationService.RecommendationPriority.Medium => "Средний",
 053        PurchaseRecommendationService.RecommendationPriority.Low => "Низкий",
 054        _ => "Неизвестно"
 055    };
 56
 057    public static string AbcDescription(char abc) => abc switch
 058    {
 059        'A' => "Класс A: 20% продуктов, обеспечивающих 80% продаж (высокая важность)",
 060        'B' => "Класс B: 30% продуктов, обеспечивающих 15% продаж (средняя важность)",
 061        'C' => "Класс C: 50% продуктов, обеспечивающих 5% продаж (низкая важность)",
 062        _ => "Неизвестный класс"
 063    };
 64
 065    public static string XyzDescription(char xyz) => xyz switch
 066    {
 067        'X' => "Класс X: Стабильный спрос (коэффициент вариации < 10%)",
 068        'Y' => "Класс Y: Умеренно изменчивый спрос (коэффициент вариации 10-25%)",
 069        'Z' => "Класс Z: Нестабильный спрос (коэффициент вариации > 25%)",
 070        _ => "Неизвестный класс"
 071    };
 72
 073    private static TrendAnalysisDto Trend(TrendAnalysisService.TrendResult t) => new()
 074    {
 075        EntityName = t.EntityName,
 076        EntityType = t.EntityType,
 077        Slope = t.Slope,
 078        Direction = DirectionName(t.Direction),
 079        R2 = t.R2,
 080        GrowthPercentage = t.GrowthPercentage,
 081        DataPointsCount = t.DataPointsCount,
 082        TrendDescription = TrendDescription(t)
 083    };
 84
 85    /// <summary>Прогноз, тренды и рекомендации по заказам-заглушкам (<see cref="AnalyticsRowProjection.ToOrders"/>).</s
 86    public static ForecastTrendAnalysisDto Build(List<OzonDomains.Models.Order> orders, int forecastDays,
 87        SalesForecastService forecast, TrendAnalysisService trends, PurchaseRecommendationService purchases)
 88    {
 89        // Остатки из системы учёта пока не подключены — как и прежде, рекомендации считаются без остатков.
 090        var recommendations = purchases.GenerateRecommendations(orders, new Dictionary<string, int>(), leadTimeDays: 7, 
 091        return new ForecastTrendAnalysisDto
 092        {
 093            SalesForecast = forecast.ForecastSales(orders, forecastDays)
 094                .Select(kvp => new SalesForecastDto { Date = kvp.Key, ForecastedSales = kvp.Value, DayOfWeek = DayOfWeek
 095            ProductTrends = trends.AnalyzeProductTrends(orders).Take(20).Select(Trend).ToList(),
 096            WarehouseTrends = trends.AnalyzeWarehouseTrends(orders).Take(10).Select(Trend).ToList(),
 097            RegionTrends = trends.AnalyzeRegionTrends(orders).Take(20).Select(Trend).ToList(),
 098            PurchaseRecommendations = recommendations.Take(20).Select(r => new PurchaseRecommendationDto
 099            {
 0100                Article = r.Article,
 0101                ProductName = r.ProductName,
 0102                CurrentStock = r.CurrentStock,
 0103                RecommendedQuantity = r.RecommendedQuantity,
 0104                RecommendedOrderDate = r.RecommendedOrderDate,
 0105                ServiceLevel = r.ServiceLevel,
 0106                Priority = PriorityName(r.Priority),
 0107                Reason = r.Reason,
 0108                ABCClass = r.ABCClass,
 0109                XYZClass = r.XYZClass,
 0110                AvgDailyDemand = r.AvgDailyDemand,
 0111                SafetyStock = r.SafetyStock,
 0112                ReorderPoint = r.ReorderPoint,
 0113                ABCDescription = AbcDescription(r.ABCClass),
 0114                XYZDescription = XyzDescription(r.XYZClass)
 0115            }).ToList()
 0116        };
 117    }
 118}