< Summary

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

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%210%
.ctor(...)100%210%
get_Key()100%210%
ExecuteAsync()0%2162460%
HasOneCGuidAsync()100%210%

File(s)

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

#LineLine coverage
 1using System.Text.RegularExpressions;
 2using Microsoft.EntityFrameworkCore;
 3using OzonDomains.Models;
 4using OzonOrdersWeb.Areas.Studio2.Controllers.Base;
 5using OzonOrdersWeb.Areas.Studio2.Models.Transactions;
 6using Services.DataServices;
 7
 8namespace OzonOrdersWeb.WebServices.Transactions.Grid.Commit.Steps;
 9
 10/// <summary>
 11/// Проверка исходных статусов (StatusTransition или дефолт определения), статусов маркетплейса,
 12/// единого поставщика/склада и наличия GUID 1С в истории — те же правила, что на GET классических страниц.
 13/// Заказы в <c>StatusOnlyWhenAlreadyIn</c> помечаются как «только статус».
 14/// </summary>
 15public sealed class ValidateSourceStatusStep : ITransactionCommitStep
 16{
 017    private static readonly Regex OneCGuid = new(
 018        "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
 019        RegexOptions.IgnoreCase | RegexOptions.Compiled);
 20
 21    private readonly StatusTransitionDataServices _transitions;
 22    private readonly TransactionDataServices _transactions;
 23    private readonly AppStatusLookup _statuses;
 24
 025    public ValidateSourceStatusStep(StatusTransitionDataServices transitions, TransactionDataServices transactions, AppS
 26    {
 027        _transitions = transitions;
 028        _transactions = transactions;
 029        _statuses = statuses;
 030    }
 31
 032    public string Key => TransactionCommitStepKeys.ValidateSourceStatus;
 33
 34    public async Task ExecuteAsync(TransactionCommitContext ctx)
 35    {
 036        var d = ctx.Definition;
 037        ctx.Transitions = d.UseStatusTransitions
 038            ? await _transitions.GetByTransactionType(d.Type)
 039            : new List<StatusTransition>();
 40
 41        // Список на странице строится из обеих сторон переходов, целевого и дополнительных статусов.
 42        // Проверка должна принимать ровно те же варианты, а не только исходную сторону перехода.
 043        var selectableIds = ctx.Transitions.SelectMany(t => new[] { t.FromStatusId, t.ToStatusId }).ToHashSet();
 044        var selectableNames = d.AllowedSourceStatuses
 045            .Concat(d.ExtraStatusNames)
 046            .Append(d.TargetStatusName)
 047            .Where(name => !string.IsNullOrWhiteSpace(name))
 048            .Distinct(StringComparer.OrdinalIgnoreCase);
 049        foreach (var name in selectableNames)
 50        {
 051            var status = await _statuses.FindAsync(name!);
 052            if (status != null)
 53            {
 054                selectableIds.Add(status.Id);
 55            }
 56        }
 057        var statusOnly = d.StatusOnlyWhenAlreadyIn.ToHashSet(StringComparer.OrdinalIgnoreCase);
 058        var disallowMarket = d.DisallowMarketplaceStatuses.ToHashSet(StringComparer.OrdinalIgnoreCase);
 59
 060        foreach (var order in ctx.Orders.ToList())
 61        {
 062            var statusName = order.AppStatus?.Name ?? string.Empty;
 063            string? problem = null;
 64
 065            if (!string.IsNullOrEmpty(order.Status) && disallowMarket.Contains(order.Status))
 66            {
 067                problem = $"Статус маркетплейса «{order.Status}» — проведение недоступно.";
 68            }
 069            else if (statusOnly.Contains(statusName))
 70            {
 071                ctx.StatusOnlyOrderIds.Add(order.Id);
 72            }
 073            else if (selectableIds.Count > 0)
 74            {
 075                if (!selectableIds.Contains(order.AppStatusId ?? 0))
 76                {
 077                    var names = string.Join(", ", ctx.Transitions
 078                        .SelectMany(t => new[] { t.FromStatus?.Name, t.ToStatus?.Name })
 079                        .Where(n => !string.IsNullOrEmpty(n))
 080                        .Distinct());
 081                    problem = $"Статус «{statusName}» не входит в допустимые: {names}.";
 82                }
 83            }
 84
 085            if (problem == null && d.RequirePriorOneCGuid && !await HasOneCGuidAsync(order.Id, ctx.CancellationToken))
 86            {
 087                problem = "У заказа нет GUID операции 1С в истории транзакций.";
 88            }
 89
 090            if (problem == null && !TransactionConfig.StandardOrderFilter(order) && d.TargetStatusName != null && !d.Pri
 91            {
 092                problem = "Заказ отменён маркетплейсом.";
 93            }
 94
 095            if (problem != null)
 96            {
 097                ctx.RowErrors[order.Id] = problem;
 98            }
 099        }
 100
 0101        if (ctx.RowErrors.Count > 0)
 102        {
 0103            var first = ctx.Orders.First(o => ctx.RowErrors.ContainsKey(o.Id));
 0104            ctx.Fail(TransactionErrorCode.InvalidSourceStatus, $"Заказ {first.ShipmentNumber}: {ctx.RowErrors[first.Id]}
 0105            return;
 106        }
 107
 0108        if (d.RequireSingleSupplierAndWarehouse)
 109        {
 0110            var inns = ctx.Orders.Select(o => o.Supplier?.INNCode?.Trim()).Where(i => !string.IsNullOrEmpty(i)).Distinct
 0111            if (inns.Count > 1)
 112            {
 0113                ctx.Fail(TransactionErrorCode.MixedSuppliers, "Все заказы должны быть от одного поставщика (по ИНН).");
 0114                return;
 115            }
 116
 0117            var warehouses = ctx.Orders.Select(o => TransactionWarehouseHelper.GetEffectiveWarehouseName(o)).Where(w => 
 0118            if (warehouses.Count > 1)
 119            {
 0120                ctx.Fail(TransactionErrorCode.MixedWarehouses, $"Заказы с разных складов: {string.Join(", ", warehouses)
 121            }
 122        }
 0123    }
 124
 125    private async Task<bool> HasOneCGuidAsync(int orderId, CancellationToken ct)
 126    {
 0127        var comments = await _transactions.GetTransactions()
 0128            .Where(t => t.Orders.Any(o => o.Id == orderId) && t.Comment != null && t.Comment != "")
 0129            .Select(t => t.Comment!)
 0130            .ToListAsync(ct);
 0131        return comments.Any(c => OneCGuid.IsMatch(c));
 0132    }
 133}