< Summary

Information
Class: OzonOrdersWeb.WebServices.Transactions.Grid.Commit.Steps.ZeroQuantityPolicyStep
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Transactions/Grid/Commit/Steps/ZeroQuantityPolicyStep.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 107
Coverable lines: 107
Total lines: 216
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 62
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%2040%
LostBySupplierAsync()0%4260%
LostByCommissionerAsync()0%2550500%

File(s)

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

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using OzonDomains;
 3using OzonDomains.Models;
 4using OzonOrdersWeb.Areas.Studio2.Helpers;
 5using OzonOrdersWeb.Areas.Studio2.Models.Transactions;
 6using OzonOrdersWeb.TransactionServices;
 7using OzonOrdersWeb.WebServices.Transactions.Grid.Definitions;
 8using OzonRepositories.Context;
 9using Services.ApiServices._1CApi;
 10using Services.DataServices;
 11using Services.StockSyncServices;
 12using Services.TransactionCommentAi;
 13using Services.TransactionUtilsServices;
 14
 15namespace OzonOrdersWeb.WebServices.Transactions.Grid.Commit.Steps;
 16
 17/// <summary>
 18/// Заказы с нулевым количеством:
 19///  - LostBySupplier (приход): статус «Утерян поставщиком», из документа исключаются;
 20///  - LostByCommissioner (отгрузка реализатору / утеря у комиссионера): транзит через
 21///    <see cref="LostByCommissionerTransitHelper"/> (остатки WS, перемещение 1С на склад утерь), статус «Утерян реализа
 22///    для ShippedToSeller — отдельная транзакция LostByCommissioner, для типа LostByCommissioner — основная.
 23/// </summary>
 24public sealed class ZeroQuantityPolicyStep : ITransactionCommitStep
 25{
 26    private readonly ApplicationDbContext _context;
 27    private readonly OrdersDataServices _orders;
 28    private readonly AppStatusDataServices _appStatuses;
 29    private readonly AppStatusLookup _statusLookup;
 30    private readonly TransactionManager _transactions;
 31    private readonly WarehouseMappingDataServices? _mappings;
 32    private readonly OneCTransferManager? _transfer;
 33    private readonly IWarehouseStockLookupService? _stockLookup;
 34
 035    public ZeroQuantityPolicyStep(
 036        ApplicationDbContext context,
 037        OrdersDataServices orders,
 038        AppStatusDataServices appStatuses,
 039        AppStatusLookup statusLookup,
 040        TransactionManager transactions,
 041        WarehouseMappingDataServices? mappings = null,
 042        OneCTransferManager? transfer = null,
 043        IWarehouseStockLookupService? stockLookup = null)
 44    {
 045        _context = context;
 046        _orders = orders;
 047        _appStatuses = appStatuses;
 048        _statusLookup = statusLookup;
 049        _transactions = transactions;
 050        _mappings = mappings;
 051        _transfer = transfer;
 052        _stockLookup = stockLookup;
 053    }
 54
 055    public string Key => TransactionCommitStepKeys.ZeroQuantityPolicy;
 56
 57    public async Task ExecuteAsync(TransactionCommitContext ctx)
 58    {
 059        switch (ctx.Definition.ZeroQuantityPolicy)
 60        {
 61            case ZeroQuantityPolicy.LostBySupplier:
 062                await LostBySupplierAsync(ctx);
 063                break;
 64            case ZeroQuantityPolicy.LostByCommissioner:
 065                await LostByCommissionerAsync(ctx);
 66                break;
 67        }
 068    }
 69
 70    private async Task LostBySupplierAsync(TransactionCommitContext ctx)
 71    {
 072        var zero = ctx.UpdatedOrders.Where(o => (o.Quantity ?? 0) <= 0).ToList();
 073        if (zero.Count == 0)
 74        {
 075            return;
 76        }
 77
 078        var status = await _statusLookup.GetOrCreateAsync("Утерян поставщиком");
 079        foreach (var o in zero)
 80        {
 081            o.AppStatus = status;
 082            o.AppStatusId = status.Id;
 83        }
 84
 085        var count = await _orders.UpdateOrders(zero);
 086        ctx.UpdatedOrders = ctx.UpdatedOrders.Where(o => (o.Quantity ?? 0) > 0).ToList();
 087        if (count > 0)
 88        {
 089            ctx.SummaryBlocks.Add($"<div class='alert alert-info'><strong>📊 Обновление статусов</strong><br/>Статус «Ут
 90        }
 091    }
 92
 93    private async Task LostByCommissionerAsync(TransactionCommitContext ctx)
 94    {
 095        if (ctx.DeferredOrderIds.Count == 0 || _stockLookup == null)
 96        {
 097            return;
 98        }
 99
 0100        var d = ctx.Definition;
 0101        var isLostType = d.Type == TransactionType.LostByCommissioner;
 0102        var deferred = ctx.Orders.Where(o => ctx.DeferredOrderIds.Contains(o.Id)).ToList();
 0103        var ids = deferred.Select(o => o.Id).ToList();
 0104        var reloaded = await _context.Orders.AsNoTracking()
 0105            .Include(o => o.OzonClient).Include(o => o.ShipmentWarehouse).Include(o => o.OrderExtensions).Include(o => o
 0106            .Where(o => ids.Contains(o.Id))
 0107            .ToListAsync(ctx.CancellationToken);
 108
 0109        var formOrders = deferred.Select(o => ApplyEditsStep.BuildFormOrder(o, ctx.Edits[o.Id], ctx)).ToList();
 0110        var manufacturerByOrderId = ctx.Edits.Values
 0111            .Where(e => ctx.DeferredOrderIds.Contains(e.Id) && !string.IsNullOrWhiteSpace(e.Manufacturer))
 0112            .ToDictionary(e => e.Id, e => e.Manufacturer!.Trim());
 113
 0114        await ctx.StageAsync("lost", "Транзит утерь", deferred.Count == 1 ? "1 заказ" : $"заказов: {deferred.Count}");
 0115        var helper = new LostByCommissionerTransitHelper(_context, _appStatuses, _mappings, _transfer, _stockLookup);
 0116        var prep = await helper.PrepareLostOrdersAsync(
 0117            formOrders, reloaded, manufacturerByOrderId, ctx.ProcessIn1C, ctx.Request.OneCOrganizationInn, ctx.User.Name
 0118            ctx.StockBlockedOrderIds);
 119
 0120        if (!string.IsNullOrWhiteSpace(prep.Fatal1CErrorHtml))
 121        {
 0122            ctx.SummaryBlocks.Add(prep.Fatal1CErrorHtml + prep.OneCSuccessHtml + prep.SkippedOrdersHtml);
 0123            ctx.Fail(TransactionErrorCode.OneCIntegrationFailed, "Ошибка 1С при транзите утерь — см. детали в результате
 0124            return;
 125        }
 126
 0127        if (!string.IsNullOrWhiteSpace(prep.SkippedOrdersHtml))
 128        {
 0129            ctx.SummaryBlocks.Add(prep.SkippedOrdersHtml);
 0130            ctx.Warnings.Add("Часть заказов без остатка в WarehouseStock пропущена.");
 131        }
 132
 0133        if (!string.IsNullOrWhiteSpace(prep.OneCSuccessHtml))
 134        {
 0135            ctx.SummaryBlocks.Add(prep.OneCSuccessHtml);
 136        }
 137
 0138        if (prep.AllOrdersSkipped)
 139        {
 0140            if (isLostType)
 141            {
 0142                ctx.Fail(TransactionErrorCode.NoOrdersForTransaction, "Все заказы пропущены: нет остатков в WarehouseSto
 143            }
 144
 0145            return;
 146        }
 147
 0148        LostByCommissionerTransitHelper.RestoreOriginalQuantities(prep.OrdersToProcess, reloaded);
 0149        var lostStatus = await _statusLookup.GetOrCreateAsync(LostByCommissionerTransitHelper.LostStatusName);
 0150        var lostOrders = new List<Order>();
 0151        foreach (var form in prep.OrdersToProcess)
 152        {
 0153            var updated = await _orders.TransactOrder(form, ApplyEditsStep.BuildSubmittedFields(ctx.Edits[form.Id]));
 0154            updated.AppStatus = lostStatus;
 0155            updated.AppStatusId = lostStatus.Id;
 0156            updated.IsVerified = true;
 0157            updated.IsAccepted = true;
 0158            lostOrders.Add(updated);
 159        }
 160
 0161        await _context.SaveChangesAsync(ctx.CancellationToken);
 162
 0163        if (isLostType)
 164        {
 165            // Основная транзакция типа «Утеря у комиссионера»: дальше идут стандартные шаги.
 0166            ctx.UpdatedOrders = lostOrders;
 0167            ctx.OneCHandledExternally = true;
 0168            if (prep.TransferResultForHistory is { Count: > 0 })
 169            {
 0170                ctx.OneCResponses.AddRange(prep.TransferResultForHistory);
 0171                ctx.OneCSender = prep.HistorySender;
 0172                ctx.OneCRecipient = prep.HistoryRecipient;
 0173                ctx.HistoryWindowStart = prep.HistoryWindowStart;
 0174                if (ctx.CommentFlow.ScheduleAiComment && ctx.CommentFlow.Builder != null)
 175                {
 0176                    ctx.CommentFlow.Builder.WithOneCResults(prep.TransferResultForHistory);
 177                }
 0178                else if (!string.IsNullOrWhiteSpace(prep.CommentAppendix))
 179                {
 0180                    ctx.TechnicalComment += prep.CommentAppendix;
 181                }
 182            }
 183
 0184            return;
 185        }
 186
 187        // ShippedToSeller: отдельная транзакция LostByCommissioner на утерянные заказы.
 0188        var comment = ctx.UserComment;
 0189        if (!string.IsNullOrWhiteSpace(prep.CommentAppendix) && !ctx.CommentFlow.ScheduleAiComment)
 190        {
 0191            comment += prep.CommentAppendix;
 192        }
 193
 0194        var commentForDb = TransactionCommentAiSchedulingHelper.ResolveDatabaseComment(ctx.CommentFlow, comment);
 0195        var (_, _, lostTransactionId) = await _transactions.CreateLostByCommissionerTransaction(lostOrders, ctx.User.Nam
 196
 0197        if (ctx.CommentFlow.ScheduleAiComment && lostTransactionId > 0)
 198        {
 0199            var builder = new TransactionCommentAiContextBuilder(TransactionType.LostByCommissioner, ctx.User.Name, Date
 0200            if (prep.TransferResultForHistory is { Count: > 0 })
 201            {
 0202                builder.WithOneCResults(prep.TransferResultForHistory);
 203            }
 204
 0205            await TransactionCommentAiSchedulingHelper.TryScheduleAsync(ctx.Services, builder, true, lostTransactionId, 
 206        }
 207
 0208        if (prep.TransferResultForHistory != null && prep.OrdersForHistory is { Count: > 0 })
 209        {
 0210            await OrderHistoryOneCPostingRecorder.TryRecordMovementAsync(ctx.Services, prep.OrdersForHistory, prep.Trans
 0211                lostTransactionId > 0 ? lostTransactionId : null, prep.HistoryWindowStart, prep.HistorySender, prep.Hist
 212        }
 213
 0214        ctx.SummaryBlocks.Add($"<div class='alert alert-info'><strong>Утеря у комиссионера</strong><br/>Заказов переведе
 0215    }
 216}