< Summary

Information
Class: OzonOrdersWeb.WebServices.Transactions.Grid.Commit.Steps.OneCStockCheckStep
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Transactions/Grid/Commit/Steps/OneCStockCheckStep.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 81
Coverable lines: 81
Total lines: 178
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 60
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
get_Key()100%210%
ExecuteAsync()0%1056320%
CheckShipToSellerAsync()0%2040%
ApplyStockCheckResult(...)0%4260%
QuantitiesFromEdits(...)0%7280%
SenderByOrder(...)100%210%
RecipientByOrder(...)100%210%
ZasylByOrder(...)0%4260%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Transactions/Grid/Commit/Steps/OneCStockCheckStep.cs

#LineLine coverage
 1using OzonDomains;
 2using OzonDomains.Models;
 3using OzonOrdersWeb.Areas.Studio2.Helpers;
 4using OzonOrdersWeb.WebServices.Transactions.Grid.Definitions;
 5using OzonOrdersWeb.WebServices.Transactions.Grid.Preview;
 6using OzonRepositories.Context;
 7using Services.ApiServices._1CApi.Stock;
 8using Services.DataServices;
 9
 10namespace OzonOrdersWeb.WebServices.Transactions.Grid.Commit.Steps;
 11
 12/// <summary>
 13/// Проверка остатков 1С до смены статусов — теми же построителями строк, что классические страницы
 14/// (склад по режиму определения). Дефицит: черновики (по умолчанию) либо пропуск 1С с предупреждением.
 15/// Приходная накладная остатков не требует.
 16/// </summary>
 17public sealed class OneCStockCheckStep : ITransactionCommitStep
 18{
 19    private readonly ApplicationDbContext _context;
 20    private readonly IOneCStockAvailabilityService? _stock;
 21    private readonly WarehouseMappingDataServices? _mappings;
 22
 23    private readonly ShipToSellerOneCPlanner? _shipToSeller;
 24    private readonly IOneCStockAlertReporter? _stockAlerts;
 25
 026    public OneCStockCheckStep(
 027        ApplicationDbContext context,
 028        IOneCStockAvailabilityService? stock = null,
 029        WarehouseMappingDataServices? mappings = null,
 030        ShipToSellerOneCPlanner? shipToSeller = null,
 031        IOneCStockAlertReporter? stockAlerts = null)
 32    {
 033        _context = context;
 034        _stock = stock;
 035        _mappings = mappings;
 036        _shipToSeller = shipToSeller;
 037        _stockAlerts = stockAlerts;
 038    }
 39
 040    public string Key => TransactionCommitStepKeys.OneCStockCheck;
 41
 42    public async Task ExecuteAsync(TransactionCommitContext ctx)
 43    {
 044        var d = ctx.Definition;
 045        ctx.StockCheck = StockCheckResult.Empty;
 046        if (!ctx.ProcessIn1C || _stock == null || d.OneCDocument is OneCDocumentKind.None or OneCDocumentKind.Receipt)
 47        {
 048            return;
 49        }
 50
 051        var ids = ctx.Orders.Where(o => !ctx.StatusOnlyOrderIds.Contains(o.Id)).Select(o => o.Id).ToList();
 052        if (ids.Count == 0)
 53        {
 054            return;
 55        }
 56
 057        await ctx.StageAsync("stock-check", "Проверяем остатки в 1С");
 058        var doc = ctx.Request.Document;
 59
 060        if (_shipToSeller != null && d.Type == TransactionType.ShippedToSeller && d.WarehouseMode == WarehouseMode.Mappi
 61        {
 062            await CheckShipToSellerAsync(ctx, ids, _shipToSeller);
 063            return;
 64        }
 65
 066        var stockOrders = await TransactionStockCheckLineBuilder.LoadForStockCheckAsync(_context, ids);
 067        var quantities = QuantitiesFromEdits(ctx);
 68
 69        IReadOnlyList<StockCheckLine> lines;
 070        switch (d.WarehouseMode)
 71        {
 72            case WarehouseMode.GlobalPair:
 73            case WarehouseMode.SenderOnly:
 074                lines = TransactionStockCheckLineBuilder.FromExplicitWarehouse(stockOrders, doc.SenderWarehouse, quantit
 075                break;
 76            case WarehouseMode.PerOrderBoth:
 077                lines = TransactionStockCheckLineBuilder.FromExplicitWarehouses(stockOrders, SenderByOrder(ctx), doc.Sen
 078                break;
 079            case WarehouseMode.Mapping when d.OneCDocument == OneCDocumentKind.Expense:
 080                lines = TransactionStockCheckLineBuilder.FromEffectiveWarehouse(stockOrders, quantities);
 081                break;
 82            case WarehouseMode.Mapping:
 083                var mappings = _mappings != null ? await _mappings.GetWarehouseMappings() : null;
 084                lines = TransactionStockCheckLineBuilder.FromWarehouseMappings(stockOrders, mappings, ZasylByOrder(ctx),
 085                break;
 86            default:
 087                lines = TransactionStockCheckLineBuilder.FromEffectiveWarehouse(stockOrders, quantities);
 88                break;
 89        }
 90
 091        ctx.StockCheck = await OneCStockGate.RunAsync(_stock, lines);
 092        await (_stockAlerts?.ReportAsync(ctx.StockCheck, "Проведение через TransactionsGrid", ctx.CancellationToken) ?? 
 093        ApplyStockCheckResult(ctx);
 094    }
 95
 96    /// <summary>
 97    /// «Отгружен реализатору»: как классика — склад основных строк по засылу и связям складов, плюс транзитные
 98    /// строки (qty = 0) с остатком WS. Нехватка по транзиту тоже уводит заказ в черновик 1С.
 99    /// </summary>
 100    private async Task CheckShipToSellerAsync(TransactionCommitContext ctx, List<int> ids, ShipToSellerOneCPlanner plann
 101    {
 0102        var zeroIds = ids.Where(id => ctx.Edits.TryGetValue(id, out var e) && ApplyEditsStep.IsZeroQuantity(e)).ToList()
 0103        var mainIds = ids.Except(zeroIds).ToList();
 0104        var manufacturers = ctx.Edits.Values
 0105            .Where(e => zeroIds.Contains(e.Id) && !string.IsNullOrWhiteSpace(e.Manufacturer))
 0106            .ToDictionary(e => e.Id, e => e.Manufacturer!.Trim());
 0107        var zasyl = ZasylByOrder(ctx).ToDictionary(kv => kv.Key, kv => (string?)kv.Value);
 108
 0109        var plan = await planner.BuildAsync(new ShipToSellerPlanRequest(mainIds, QuantitiesFromEdits(ctx), zasyl, zeroId
 0110        ctx.StockCheck = await planner.CheckStockAsync(plan);
 0111        await (_stockAlerts?.ReportAsync(ctx.StockCheck, "Отгружен реализатору через TransactionsGrid", ctx.Cancellation
 0112        ApplyStockCheckResult(ctx);
 0113    }
 114
 115    private static void ApplyStockCheckResult(TransactionCommitContext ctx)
 116    {
 0117        var check = ctx.StockCheck!;
 0118        if (!check.HasBlocking)
 119        {
 0120            return;
 121        }
 122
 0123        foreach (var id in OneCStockGate.GetBlockingOrderIds(check))
 124        {
 0125            ctx.StockBlockedOrderIds.Add(id);
 126        }
 127
 0128        if (ctx.Request.Document.CreateDraftsOnShortage)
 129        {
 130            // Дефицитные позиции уйдут отдельным черновиком (OneCDocumentStep).
 0131            return;
 132        }
 133
 134        // Классическое безопасное поведение: 1С не вызывается, статусы и документ Studio2 создаются.
 0135        ctx.ProcessIn1C = false;
 0136        ctx.SummaryBlocks.Add(OneCStockShortageHtmlBuilder.Build(check));
 0137        ctx.Warnings.Add("Недостаточно остатка в 1С — документ 1С не создан, статусы изменены.");
 0138    }
 139
 140    internal static Dictionary<int, decimal> QuantitiesFromEdits(TransactionCommitContext ctx)
 141    {
 0142        var result = new Dictionary<int, decimal>();
 0143        foreach (var o in ctx.Orders)
 144        {
 0145            var edit = ctx.Edits[o.Id];
 0146            var qty = edit.Changed.Contains("quantity", StringComparer.OrdinalIgnoreCase) && edit.Quantity.HasValue ? ed
 0147            if (qty > 0)
 148            {
 0149                result[o.Id] = qty;
 150            }
 151        }
 152
 0153        return result;
 154    }
 155
 156    internal static Dictionary<int, string> SenderByOrder(TransactionCommitContext ctx)
 0157        => ctx.Edits.Values.Where(e => !string.IsNullOrWhiteSpace(e.SenderWarehouse)).ToDictionary(e => e.Id, e => e.Sen
 158
 159    internal static Dictionary<int, string> RecipientByOrder(TransactionCommitContext ctx)
 0160        => ctx.Edits.Values.Where(e => !string.IsNullOrWhiteSpace(e.RecipientWarehouse)).ToDictionary(e => e.Id, e => e.
 161
 162    /// <summary>Засыл: изменённый в строке или текущий из OrderExtension.</summary>
 163    internal static Dictionary<int, string> ZasylByOrder(TransactionCommitContext ctx)
 164    {
 0165        var map = new Dictionary<int, string>();
 0166        foreach (var o in ctx.Orders)
 167        {
 0168            var edit = ctx.Edits[o.Id];
 0169            var value = edit.Changed.Contains("zasyl", StringComparer.OrdinalIgnoreCase) ? edit.Zasyl : Areas.Studio2.Co
 0170            if (!string.IsNullOrWhiteSpace(value))
 171            {
 0172                map[o.Id] = value.Trim();
 173            }
 174        }
 175
 0176        return map;
 177    }
 178}