< Summary

Information
Class: Services.BackgroundJobsServices.ShippedToCommissionerWarehouseResolver
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/BackgroundJobsServices/ShippedToCommissionerWarehouseResolver.cs
Line coverage
96%
Covered lines: 56
Uncovered lines: 2
Coverable lines: 58
Total lines: 136
Line coverage: 96.5%
Branch coverage
73%
Covered branches: 53
Total branches: 72
Branch coverage: 73.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ResolveSenderWarehouse(...)100%11100%
ResolveSender(...)85%2020100%
ResolveTransitWarehouse(...)50%232287.5%
GetWarehouseMappingName(...)100%22100%
ResolveBestMapping(...)92.85%1414100%
GetMappingDeliveryType(...)71.42%1414100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/BackgroundJobsServices/ShippedToCommissionerWarehouseResolver.cs

#LineLine coverage
 1using OzonDomains.Models;
 2
 3namespace Services.BackgroundJobsServices;
 4
 5/// <summary>
 6/// Склад-отправитель и признак того, что имя пришло из WarehouseMapping, а не взято как есть.
 7/// </summary>
 8public readonly record struct WarehouseResolution(string? Warehouse, bool FromMapping);
 9public readonly record struct TransitWarehouseResolution(string? SenderWarehouse, string? TransitWarehouse);
 10
 11/// <summary>
 12/// Склад отправителя для документов 1С: BitrixWarehouseName из WarehouseMapping по клиенту Ozon,
 13/// приоритетному ключу «Засыл» либо складу заказа и, если он задан в маппинге, типу доставки.
 14/// </summary>
 15public static class ShippedToCommissionerWarehouseResolver
 16{
 17    public const string ZasylKey = "Засыл";
 18    private const string EmexClientName = "Эмекс";
 19
 20    public static string? ResolveSenderWarehouse(Order order, IReadOnlyList<WarehouseMapping> mappings)
 21    {
 2822        return ResolveSender(order, mappings).Warehouse;
 23    }
 24
 25    /// <summary>
 26    /// Тот же резолв, но с возможностью подставить засыл извне (значение поля формы, ещё не
 27    /// сохранённое в OrderExtensions) и узнать, нашлась ли связь складов.
 28    /// </summary>
 29    public static WarehouseResolution ResolveSender(
 30        Order order,
 31        IReadOnlyList<WarehouseMapping> mappings,
 32        string? zasylOverride = null)
 33    {
 4634        if (order == null)
 35        {
 136            return new WarehouseResolution(null, false);
 37        }
 38
 4539        var zasyl = !string.IsNullOrWhiteSpace(zasylOverride)
 4540            ? zasylOverride.Trim()
 4541            : order.OrderExtensions?
 542                .FirstOrDefault(e => string.Equals(e.Key, ZasylKey, StringComparison.OrdinalIgnoreCase))
 4543                ?.Value?
 4544                .Trim();
 4545        var shipmentWarehouseName = order.ShipmentWarehouse?.Name?.Trim();
 4546        var warehouseMappingName = GetWarehouseMappingName(zasyl, shipmentWarehouseName);
 4547        if (!order.OzonClientId.HasValue || string.IsNullOrWhiteSpace(warehouseMappingName))
 48        {
 949            return new WarehouseResolution(warehouseMappingName, false);
 50        }
 51
 3652        var best = ResolveBestMapping(order, mappings, warehouseMappingName);
 53
 3654        if (best != null)
 55        {
 2856            return new WarehouseResolution(best.BitrixWarehouseName.Trim(), true);
 57        }
 58
 859        return new WarehouseResolution(warehouseMappingName, false);
 60    }
 61
 62    /// <summary>Транзитный склад берётся только из выбранной связи WarehouseMapping.</summary>
 63    public static TransitWarehouseResolution ResolveTransitWarehouse(
 64        Order order,
 65        IReadOnlyList<WarehouseMapping> mappings)
 66    {
 367        var sender = ResolveSender(order, mappings);
 368        if (order == null || !order.OzonClientId.HasValue || string.IsNullOrWhiteSpace(sender.Warehouse))
 069            return new TransitWarehouseResolution(sender.Warehouse, null);
 70
 371        var mappingName = GetWarehouseMappingName(
 372            order.OrderExtensions?
 073                .FirstOrDefault(e => string.Equals(e.Key, ZasylKey, StringComparison.OrdinalIgnoreCase))
 374                ?.Value?.Trim(),
 375            order.ShipmentWarehouse?.Name?.Trim());
 376        var mapping = string.IsNullOrWhiteSpace(mappingName)
 377            ? null
 378            : ResolveBestMapping(order, mappings, mappingName);
 379        return new TransitWarehouseResolution(
 380            sender.Warehouse,
 381            string.IsNullOrWhiteSpace(mapping?.TransitBitrixWarehouseName)
 382                ? null
 383                : mapping.TransitBitrixWarehouseName.Trim());
 84    }
 85
 86    private static string? GetWarehouseMappingName(string? zasyl, string? shipmentWarehouseName) =>
 4887        WarehouseNameNormalizer.Normalize(!string.IsNullOrWhiteSpace(zasyl) ? zasyl : shipmentWarehouseName);
 88
 89    private static WarehouseMapping? ResolveBestMapping(
 90        Order order,
 91        IReadOnlyList<WarehouseMapping> mappings,
 92        string warehouseMappingName)
 93    {
 3994        var candidates = mappings
 5195            .Where(m => m.OzonClientId == order.OzonClientId &&
 5196                        !string.IsNullOrWhiteSpace(m.OzonWarehouseName) &&
 5197                        !string.IsNullOrWhiteSpace(m.BitrixWarehouseName) &&
 5198                        string.Equals(WarehouseNameNormalizer.Normalize(m.OzonWarehouseName), warehouseMappingName,
 5199                            StringComparison.OrdinalIgnoreCase))
 39100            .ToList();
 101
 39102        var deliveryName = GetMappingDeliveryType(order);
 39103        if (!string.IsNullOrWhiteSpace(deliveryName))
 104        {
 17105            var exactDeliveryCandidates = candidates
 13106                .Where(m => string.Equals(m.DeliveryType?.Trim(), deliveryName, StringComparison.OrdinalIgnoreCase))
 17107                .ToList();
 17108            candidates = exactDeliveryCandidates.Count > 0
 17109                ? exactDeliveryCandidates
 17110                : candidates.Where(m => string.IsNullOrWhiteSpace(m.DeliveryType)).ToList();
 111        }
 112        else
 113        {
 114            // Для клиентов кроме Эмекс сначала используем общую связь без типа доставки.
 115            // Если её нет, сохраняем доступную связь (например, Interparts RU + M1 + Ozon).
 22116            var genericCandidates = candidates
 25117                .Where(m => string.IsNullOrWhiteSpace(m.DeliveryType))
 22118                .ToList();
 22119            if (genericCandidates.Count > 0)
 14120                candidates = genericCandidates;
 121        }
 122
 111123        return candidates.OrderBy(m => m.Priority).ThenBy(m => m.Id).FirstOrDefault();
 124    }
 125
 126    /// <summary>
 127    /// Тип доставки, который резолвер учитывает при отборе связей: заполнен только для Эмекс.
 128    /// Нужен и снаружи — чтобы предложенная пользователю новая связь действительно применилась.
 129    /// </summary>
 130    public static string? GetMappingDeliveryType(Order? order)
 131    {
 48132        var isEmexOrder = string.Equals(
 48133            order?.OzonClient?.Name?.Trim(), EmexClientName, StringComparison.OrdinalIgnoreCase);
 48134        return isEmexOrder ? order?.Delivery?.Name?.Trim() : null;
 135    }
 136}