< Summary

Information
Class: OzonOrdersWeb.WebServices.Orders.Grid.OrderGridRowMapper
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Orders/Grid/OrderGridRowMapper.cs
Line coverage
86%
Covered lines: 174
Uncovered lines: 28
Coverable lines: 202
Total lines: 371
Line coverage: 86.1%
Branch coverage
69%
Covered branches: 174
Total branches: 250
Branch coverage: 69.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
MapBlock(...)71.05%413887.87%
Map(...)73.41%17815890.78%
IsCancelled(...)92.85%1414100%
ResolveRowTone(...)100%1414100%
Extension(...)50%44100%
BuildCancellationReason(...)6.25%1241625%
BuildSupplierTooltip(...)16.66%27616.66%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Orders/Grid/OrderGridRowMapper.cs

#LineLine coverage
 1using OzonDomains;
 2using OzonDomains.Models;
 3
 4namespace OzonOrdersWeb.WebServices.Orders.Grid;
 5
 6/// <summary>
 7/// Чистое преобразование <see cref="Order"/> → <see cref="OrderGridRowDto"/>.
 8/// Правила тона строки и группировки по отправлению повторяют <c>_IndexTableBody.cshtml</c>.
 9/// Гейтинг: поля закрытых колонок остаются null (см. <see cref="OrdersGridColumnAccess"/>).
 10/// </summary>
 11public static class OrderGridRowMapper
 12{
 13    public static List<OrderGridRowDto> MapBlock(
 14        IReadOnlyList<Order> orders,
 15        IReadOnlySet<string> allowedColumns,
 16        IReadOnlyDictionary<string, bool>? labelExists,
 17        bool groupByShipment,
 18        string? groupBy = null)
 19    {
 220        var groupSizes = new Dictionary<long, int>();
 221        if (groupByShipment)
 22        {
 1023            foreach (var o in orders)
 24            {
 425                if (o.ShipmentId.HasValue)
 26                {
 327                    groupSizes[o.ShipmentId.Value] = groupSizes.GetValueOrDefault(o.ShipmentId.Value) + 1;
 28                }
 29            }
 30        }
 31
 232        var result = new List<OrderGridRowDto>(orders.Count);
 233        long? previousShipmentId = null;
 234        var groupKeyMode = groupBy != null && OrdersGridGrouping.Supports(groupBy) && !OrdersGridGrouping.IsShipment(gro
 235        string? previousGroupKey = null;
 236        var first = true;
 1637        foreach (var order in orders)
 38        {
 639            string? position = null;
 640            var groupSize = 0;
 641            if (groupByShipment && order.ShipmentId.HasValue)
 42            {
 343                groupSize = groupSizes.GetValueOrDefault(order.ShipmentId.Value, 1);
 344                if (groupSize > 1)
 45                {
 246                    position = order.ShipmentId != previousShipmentId ? "first" : "continuation";
 47                }
 348                previousShipmentId = order.ShipmentId;
 49            }
 50            else
 51            {
 352                previousShipmentId = null;
 53            }
 54
 655            var row = Map(order, allowedColumns, labelExists);
 656            row.ShipmentGroupPosition = position;
 657            row.ShipmentGroupSize = groupSize;
 658            if (groupKeyMode)
 59            {
 060                var key = OrdersGridGrouping.KeyOf(order, groupBy!) ?? string.Empty;
 061                row.GroupKey = key;
 062                row.GroupPosition = first || !string.Equals(key, previousGroupKey, StringComparison.Ordinal) ? "first" :
 063                previousGroupKey = key;
 64            }
 665            else if (groupByShipment)
 66            {
 467                row.GroupKey = order.ShipmentId?.ToString();
 468                row.GroupPosition = position == "continuation" ? "continuation" : "first";
 69            }
 70
 671            first = false;
 672            result.Add(row);
 73        }
 74
 275        return result;
 76    }
 77
 78    public static OrderGridRowDto Map(
 79        Order o,
 80        IReadOnlySet<string> allowed,
 81        IReadOnlyDictionary<string, bool>? labelExists)
 82    {
 1183        var row = new OrderGridRowDto
 1184        {
 1185            Id = o.Id,
 1186            ShipmentId = o.ShipmentId,
 1187            CartItemId = o.CartItemId,
 1188            IsArchived = o.OrderArchive != null,
 1189            IsReturned = o.IsReturned,
 1190            IsReturnable = o.IsReturnable == true,
 1191            IsCancelled = IsCancelled(o),
 1192            MarketStatus = o.Status,
 1193            FromFile = o.FromFile == true,
 1194            HasOzonPromotion = o.OzonPromotionSnapshot?.HasAnyPromotion == true,
 1195            HasTransactionDocument = !string.IsNullOrEmpty(Extension(o, "Документ транзакции")),
 1196            ClientKind = o.OzonClient?.ClientType switch
 1197            {
 998                ClientType.OZON => "ozon",
 099                ClientType.YANDEX => "yandex",
 2100                _ => "other"
 11101            }
 11102        };
 11103        row.RowTone = ResolveRowTone(o, row.IsCancelled);
 11104        if (o.Problems is { Count: > 0 })
 2105            row.Problems = o.Problems.Select(x => new OrderGridProblemDto(x.Severity, x.Kind, x.Text)).ToList();
 106
 11107        if (!string.IsNullOrEmpty(o.ShipmentNumber) && labelExists != null
 11108            && labelExists.TryGetValue(o.ShipmentNumber, out var exists))
 109        {
 1110            row.LabelExists = exists;
 111        }
 112
 11113        if (allowed.Contains("ShipmentNumber"))
 114        {
 9115            row.ShipmentNumber = o.ShipmentNumber;
 9116            row.Scanit = o.Scanit;
 117        }
 118
 11119        if (allowed.Contains("Delivery"))
 120        {
 8121            row.DeliveryProvider = o.Delivery?.Provider?.Name;
 122        }
 123
 11124        if (allowed.Contains("DeliveryType"))
 125        {
 8126            row.DeliveryName = o.Delivery?.Name;
 127        }
 128
 11129        if (allowed.Contains("TrackingNumber"))
 130        {
 8131            row.TrackingNumber = o.TrackingNumber;
 132        }
 133
 11134        if (allowed.Contains("OzonClient"))
 135        {
 9136            row.OzonClient = o.OzonClient?.Name;
 9137            row.OzonClientType = o.OzonClient?.ClientType.ToString();
 138        }
 139
 11140        if (allowed.Contains("DeliveryCity"))
 141        {
 8142            row.DeliveryCity = o.DeliveryCity;
 143        }
 144
 11145        if (allowed.Contains("ProcessingDate"))
 146        {
 8147            row.ProcessingDate = o.ProcessingDate;
 8148            row.ProcessingDateText = OrderDateDisplay.FormatTableDateFull(o.ProcessingDate);
 8149            row.ProcessingDateFull = o.FullFormattedProcessingDate;
 150        }
 151
 11152        if (allowed.Contains("ShippingDate"))
 153        {
 8154            row.ShippingDate = o.ShippingDate;
 8155            row.ShippingDateText = OrderDateDisplay.FormatTableDateFull(o.ShippingDate);
 8156            row.ShippingDateFull = o.FullFormattedShippingDate;
 157        }
 158
 11159        if (allowed.Contains("DeliveryPeriod"))
 160        {
 8161            row.DeliveryPeriodText = o.FormattedDeliveryDay;
 8162            row.DeliveryPeriodHoursText = o.FormattedDeliveryHours;
 8163            row.TimeLeftText = o.FormattedTimeLeftDay;
 8164            var timeLeft = o.TimeLeft;
 8165            row.TimeLeftDays = timeLeft?.Days;
 8166            row.DeliveryOverdue = timeLeft.HasValue && timeLeft.Value < TimeSpan.Zero;
 167        }
 168
 11169        if (allowed.Contains("ProductKey"))
 170        {
 8171            row.ProductKey = o.ProductKey;
 8172            row.ImageUrl = o.ProductInfo?.ImageUrl;
 8173            row.Barcode = o.ProductInfo?.Barcode;
 174        }
 175
 11176        if (allowed.Contains("Manufacturer"))
 177        {
 8178            row.Manufacturer = o.EtProducer?.Name;
 8179            row.EtProducerId = o.EtProducer?.Id;
 180        }
 181
 11182        if (allowed.Contains("Article"))
 183        {
 8184            row.Article = o.Article;
 8185            row.ReplacementArticle = o.ProductInfo?.ReplacementProduct?.Article;
 186        }
 187
 11188        if (allowed.Contains("ProductName"))
 189        {
 8190            row.ProductName = o.ProductName;
 191        }
 192
 11193        if (allowed.Contains("ClientStatus"))
 194        {
 8195            row.ClientStatus = o.ClientStatus?.Name;
 8196            row.ClientStatusColor = o.ClientStatus?.StatusColor?.ColorCode;
 8197            row.CancellationReason = BuildCancellationReason(o);
 198        }
 199
 11200        if (allowed.Contains("AppStatus"))
 201        {
 8202            row.AppStatus = o.AppStatus?.Name;
 8203            row.AppStatusColor = o.AppStatus?.StatusColor?.ColorCode;
 8204            row.AppStatusIsFinal = o.AppStatus?.IsFinal == true;
 8205            row.CartItemStatus = o.CartItemStatus?.Name;
 8206            row.CartItemStatusColor = o.CartItemStatusColor?.ColorCode;
 8207            row.CartItemStatusId = o.CartItemStatus?.Id;
 8208            row.SupplierStatus = o.SupplierStatusName;
 8209            row.SupplierStatusColor = o.SupplierStatusColor;
 8210            row.SupplierStatusProviderKey = o.SupplierStateProviderKey;
 8211            row.SupplierStatusTooltip = BuildSupplierTooltip(o);
 8212            row.SupplierExpectedDeliveryText = o.SupplierExpectedDeliveryDate.HasValue ? o.FormattedSupplierExpectedDeli
 8213            row.SupplierExpectedDeliveryDaysLeft = o.FormattedSupplierExpectedDeliveryDaysLeft;
 8214            row.ReturnStatusText = string.IsNullOrWhiteSpace(o.ReturnStatusDisplayName) ? o.ReturnStatusSysName : o.Retu
 215        }
 216
 11217        if (allowed.Contains("ShipmentWarehouse"))
 218        {
 8219            row.ShipmentWarehouse = o.ShipmentWarehouse?.Name;
 8220            row.ZasylWarehouse = Extension(o, "Засыл");
 8221            row.ReturnWarehouseName = o.ReturnWarehouseName;
 222        }
 223
 11224        if (allowed.Contains("LastStatusChangeDate"))
 225        {
 8226            row.LastStatusChangeDate = o.LastStatusChangeDate;
 8227            row.LastStatusChangeDateText = o.FormattedLastStatusChangeDate;
 8228            row.LastStatusChangeDateFull = o.FullFormattedLastStatusChangeDate;
 229        }
 230
 11231        if (allowed.Contains("Supplier"))
 232        {
 8233            row.Supplier = o.Supplier?.Name;
 8234            row.SupplierDirection = o.SupplierStateDirection;
 235        }
 236
 11237        if (allowed.Contains("SupplierOrderNumber"))
 238        {
 8239            row.OrderNumberToSupplier = o.OrderNumberToSupplier;
 240        }
 241
 11242        if (allowed.Contains("Category"))
 243        {
 8244            row.Category = o.ProductInfo?.CommercialCategory;
 245        }
 246
 11247        if (allowed.Contains("VolumeWeight") && o.ProductInfo != null)
 248        {
 0249            row.VolumetricWeight = o.ProductInfo.VolumetricWeight;
 0250            row.Weight = o.ProductInfo.Weight;
 251        }
 252
 11253        if (allowed.Contains("SitePrice"))
 254        {
 8255            row.SitePrice = o.ProductInfo?.CurrentPriceWithDiscount;
 256        }
 257
 11258        if (allowed.Contains("Quantity"))
 259        {
 8260            row.Quantity = o.Quantity;
 261        }
 262
 11263        if (allowed.Contains("Price"))
 264        {
 8265            row.Price = o.Price;
 8266            row.Currency = o.Сurrency?.Name;
 8267            row.PriceIndexColor = o.OrderPrice?.PriceIndexes?.ColorIndex;
 268        }
 269
 11270        if (allowed.Contains("ShipmentTotal"))
 271        {
 8272            row.ShipmentAmount = o.ShipmentAmount;
 273        }
 274
 11275        if (allowed.Contains("PurchasePrice"))
 276        {
 8277            row.PurchasePrice = o.PurchasePrice;
 278        }
 279
 11280        if (allowed.Contains("Cost"))
 281        {
 8282            row.CostPrice = o.CostPrice;
 8283            var expenses = (o.ExtraExpenses ?? [])
 0284                .Where(e => e.ExpenseTypeId > 0 && e.Amount > 0)
 8285                .ToList();
 8286            if (expenses.Count > 0)
 287            {
 0288                row.ExtraExpenses = expenses.Sum(e => e.Amount);
 0289                row.ExtraExpensesItems = expenses
 0290                    .Select(e => new OrderGridExtraExpenseDto
 0291                    {
 0292                        Type = e.ExpenseType?.Name ?? string.Empty,
 0293                        Amount = e.Amount,
 0294                        Comment = e.Comment
 0295                    })
 0296                    .ToList();
 297            }
 298        }
 299
 11300        if (allowed.Contains("OzonCommission"))
 301        {
 8302            row.OzonCommissionMin = o.MinOzonCommission;
 8303            row.OzonCommissionMax = o.MaxOzonCommission;
 304        }
 305
 11306        if (allowed.Contains("Profit"))
 307        {
 8308            row.ProfitMin = o.MinProfit;
 8309            row.ProfitMax = o.MaxProfit;
 8310            row.TargetProfit135 = o.TargetShipmentProfit135;
 311        }
 312
 11313        if (allowed.Contains("MarkupPercent"))
 314        {
 8315            row.DiscountMin = o.MinDiscount;
 8316            row.DiscountMax = o.MaxDiscount;
 317        }
 318
 11319        return row;
 320    }
 321
 322    /// <summary>Правило «отменён» из _IndexTableBody: красная строка.</summary>
 323    public static bool IsCancelled(Order o)
 324    {
 18325        var client = o.ClientStatus?.Name;
 18326        return (o.AppStatus?.Name == "Отменен" && (client == "Отменён" || o.ClientStatus == null))
 18327               || client is "Отменен" or "Отменён";
 328    }
 329
 330    public static string? ResolveRowTone(Order o, bool isCancelled)
 331    {
 22332        if (isCancelled) return "danger";
 17333        if (o.IsReturnable == true) return "returnable";
 15334        return o.AppStatus?.Name switch
 15335        {
 2336            "Заказан поставщику" => "success",
 1337            "Отгружен поставщиком" => "info",
 1338            "Отгружен реализатору" => "warning",
 1339            "Заказан реализатору" => "secondary",
 10340            _ => null
 15341        };
 342    }
 343
 344    private static string? Extension(Order o, string key)
 19345        => o.OrderExtensions?.FirstOrDefault(e => e.Key == key)?.Value;
 346
 347    private static string? BuildCancellationReason(Order o)
 348    {
 8349        var c = o.LatestOzonPostingCancellation;
 16350        if (c == null) return null;
 0351        if (string.IsNullOrWhiteSpace(c.ReasonTitle) && string.IsNullOrWhiteSpace(c.ReasonMessage)) return null;
 352
 0353        var text = $"Причина отмены: {c.ReasonTitle ?? c.ReasonMessage}";
 0354        if (c.ReasonId.HasValue) text += $" (ID: {c.ReasonId})";
 0355        if (!string.IsNullOrWhiteSpace(c.ReasonTypeId)) text += $"; инициатор: {c.ReasonTypeId}";
 0356        if (!string.IsNullOrWhiteSpace(c.ReasonMessage) && c.ReasonMessage != c.ReasonTitle) text += $"; {c.ReasonMessag
 0357        return text;
 358    }
 359
 360    private static string? BuildSupplierTooltip(Order o)
 361    {
 16362        if (string.IsNullOrWhiteSpace(o.SupplierStatusName)) return null;
 0363        var supplierName = o.SupplierStateSupplierName ?? o.SupplierStateProviderKey;
 0364        var tooltip = $"{supplierName}: {o.SupplierStatusName}";
 0365        if (!string.IsNullOrWhiteSpace(o.SupplierStateExternalOrderNumber))
 366        {
 0367            tooltip += $" · заказ {o.SupplierStateExternalOrderNumber}";
 368        }
 0369        return tooltip;
 370    }
 371}