< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_Shared__TransactionErrorPanel
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/Shared/_TransactionErrorPanel.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 178
Coverable lines: 178
Total lines: 292
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 91
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()0%5550740%
GetIssueTitle()0%306170%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/Shared/_TransactionErrorPanel.cshtml

#LineLine coverage
 1@using System.Text.RegularExpressions
 2@using OzonOrdersWeb.Areas.Studio2.Models.Transactions
 3@{
 04    var controllerName = (ViewContext.RouteData.Values["controller"]?.ToString() ?? string.Empty).Trim();
 05    var actionName = (ViewContext.RouteData.Values["action"]?.ToString() ?? string.Empty).Trim();
 06    var rawErrorReason = ViewData["ErrorReason"]?.ToString()?.Trim() ?? string.Empty;
 07    var rawConditions = ViewData["TransactionConditionsMessage"]?.ToString()?.Trim() ?? string.Empty;
 8
 09    var statusTransitionsUrl = Url.Action("Index", "StatusTransition", new { area = "Studio2" }) ?? "/Studio2/StatusTran
 010    var appStatusesUrl = Url.Action("Index", "AppStatus", new { area = "Studio2" }) ?? "/Studio2/AppStatus";
 011    var suppliersUrl = Url.Action("Index", "Supplier", new { area = "Studio2" }) ?? "/Studio2/Supplier";
 012    var warehousesUrl = Url.Action("Index", "Warehouse", new { area = "Studio2" }) ?? "/Studio2/Warehouse";
 013    var warehouseMappingUrl = Url.Action("Index", "WarehouseMapping", new { area = "Studio2" }) ?? "/Studio2/WarehouseMa
 014    var ordersUrl = Url.Action("Index", "Orders", new { area = "Studio2" }) ?? "/Studio2/Orders";
 015    var editAllIds = Context.Request.Query["ids"].ToString();
 016    var editAllUrl = !string.IsNullOrWhiteSpace(editAllIds)
 017        ? Url.Action("MultiplayEditV2", "Orders", new { area = "Studio2", ids = editAllIds, page = 1 })
 018        : null;
 19
 020    var errorCodeRaw = ViewData["TransactionErrorCode"]?.ToString();
 021    var errorCode = Enum.TryParse<TransactionErrorCode>(errorCodeRaw, out var parsedErrorCode)
 022        ? parsedErrorCode
 023        : TransactionErrorCode.Unknown;
 24
 025    var normalizedController = controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)
 026        ? controllerName[..^10]
 027        : controllerName;
 28
 29    string GetIssueTitle(TransactionErrorCode code)
 30    {
 031        if (code == TransactionErrorCode.NoOrdersForTransaction &&
 032            string.Equals(normalizedController, "CancelledTransaction", StringComparison.OrdinalIgnoreCase))
 33        {
 034            return "Нет заказов для перевода в статус «Отменен».";
 35        }
 36
 037        return code switch
 038        {
 039            TransactionErrorCode.NoOrdersSelected => "Заказы не выбраны.",
 040            TransactionErrorCode.InvalidSourceStatus => "Статус заказа не подходит для выбранной транзакции.",
 041            TransactionErrorCode.NoOrdersForTransaction => "Нет подходящих заказов для проведения транзакции.",
 042            TransactionErrorCode.MixedSuppliers => "Выбраны заказы с разными поставщиками.",
 043            TransactionErrorCode.MixedWarehouses => "Выбраны заказы с разными складами.",
 044            TransactionErrorCode.SupplierInnMissing => "Не заполнен ИНН поставщика.",
 045            TransactionErrorCode.OneCSenderWarehouseMissing => "Не указан склад отправителя.",
 046            TransactionErrorCode.OneCRecipientWarehouseMissing => "Не указан склад получателя.",
 047            TransactionErrorCode.OneCWarehousesMustDiffer => "Склад отправителя и получателя совпадают.",
 048            TransactionErrorCode.OneCUnavailable => "Интеграция с 1С недоступна.",
 049            TransactionErrorCode.OneCIntegrationFailed => "Ошибка при передаче данных в 1С.",
 050            TransactionErrorCode.OneCInsufficientStock => "Недостаточно остатков на складе 1С.",
 051            _ => "Ошибка проверки условий проведения."
 052        };
 53    }
 54
 055    var issueTitle = GetIssueTitle(errorCode);
 56
 057    var transactionTips = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase)
 058    {
 059        ["ShippedBySupplierTransaction"] = new()
 060        {
 061            "Проверьте, что выбранные заказы в статусе \"Заказан поставщику\".",
 062            "Для проведения в 1С заполните ИНН поставщика и договор 1С у поставщика.",
 063            "Если требуется экспорт в 1С, заполните \"Страна происхождения\" и \"Номер ГТД\" в строках."
 064        },
 065        ["AcceptedToWarehouseTransaction"] = new()
 066        {
 067            "Проверьте, что статус заказа допускает приемку на склад согласно настройкам переходов.",
 068            "Убедитесь, что выбран корректный склад и поставщик.",
 069            "Если заказов несколько, используйте одинаковые обязательные параметры для всех строк."
 070        },
 071        ["ShippedToClientTransaction"] = new()
 072        {
 073            "Проверьте статус заказа: должен соответствовать правилам отгрузки клиенту.",
 074            "Убедитесь, что заполнены обязательные поля для печати/проведения.",
 075            "Если включено проведение в 1С, проверьте корректность реквизитов документа."
 076        },
 077        ["ShippedToSellerTransaction"] = new()
 078        {
 079            "Проверьте, что заказы готовы к отгрузке реализатору и имеют допустимый исходный статус.",
 080            "Заказы в одном запуске должны быть совместимы по условиям поставщика/склада.",
 081            "Проверьте заполнение обязательных реквизитов по каждой строке."
 082        },
 083        ["ReturnToSupplierTransaction"] = new()
 084        {
 085            "Проверьте, что заказы имеют разрешенный статус для возврата поставщику.",
 086            "Заполните номер заказа поставщику и комментарий, если это требуется процессом.",
 087            "При проведении в 1С убедитесь, что выбраны разные склады отправителя и получателя."
 088        },
 089        ["ReturnToWarehouseTransaction"] = new()
 090        {
 091            "Проверьте статус приложения: заказ должен подходить для возврата на склад.",
 092            "Проверьте корректность клиента и связанного 1С-документа (GUID в истории транзакций).",
 093            "Если есть группировка по складам, у всех заказов должен быть определен склад-получатель."
 094        },
 095        ["WarehouseTransferTransaction"] = new()
 096        {
 097            "Выберите склад отправителя и склад получателя.",
 098            "Склады отправителя и получателя не должны совпадать.",
 099            "Проверьте, что заказы не имеют статусов, запрещающих складское перемещение."
 0100        },
 0101        ["ShippedToCommissionerTransaction"] = new()
 0102        {
 0103            "Проверьте, что выбранные заказы можно отгрузить комиссионеру по текущим правилам StatusTransition.",
 0104            "Для проведения в 1С у всех заказов должны быть единый поставщик и единый эффективный склад.",
 0105            "Проверьте корректность клиента Ozon и складов перед массовым проведением."
 0106        },
 0107        ["WarehouseChangeTransaction"] = new()
 0108        {
 0109            "Заполните поле склада и поставщика в строках, где требуются изменения.",
 0110            "Проверьте, что сохраняемые изменения не конфликтуют с текущим статусом заказа.",
 0111            "Если изменяете несколько полей сразу, проверьте итоговые значения перед сохранением."
 0112        },
 0113        ["CustomerReturnTransaction"] = new()
 0114        {
 0115            "Для возврата покупателя нужен подходящий Ozon/клиентский статус.",
 0116            "Если включено проведение в 1С, проверьте склад отправителя/получателя для каждой строки.",
 0117            "Проверьте, что заказ действительно ранее был отгружен клиенту."
 0118        },
 0119        ["CancelledTransaction"] = new()
 0120        {
 0121            "Убедитесь, что заказ можно переводить в статус \"Отменен\" по текущим правилам переходов.",
 0122            "Проверьте, что выбраны именно нужные заказы перед массовым проведением.",
 0123            "Если есть доп. ограничения в переходах, проверьте их в справочнике StatusTransition."
 0124        },
 0125        ["ToCancellationTransaction"] = new()
 0126        {
 0127            "Проверьте, что заказ можно перевести в статус \"К отмене\".",
 0128            "Проверьте права и ограничения профиля доступа на изменение статусов.",
 0129            "Проверьте текущие условия в правилах переходов статусов."
 0130        },
 0131        ["OrderToSupplierTransaction"] = new()
 0132        {
 0133            "Проверьте, что выбранные заказы подходят для отправки поставщику.",
 0134            "Заполните поставщика, цену закупки и обязательные поля по строкам.",
 0135            "При массовой обработке убедитесь, что нет смешанных некорректных статусов."
 0136        },
 0137        ["OrderedToSellerTransaction"] = new()
 0138        {
 0139            "Проверьте, что статус заказа разрешает перевод в \"Заказан реализатору\".",
 0140            "Заполните обязательные поля поставщика/реализатора.",
 0141            "Если условие не выполняется, сначала проведите промежуточную транзакцию."
 0142        }
 0143    };
 144
 0145    var tips = transactionTips.TryGetValue(normalizedController, out var specificTips)
 0146        ? specificTips
 0147        : new List<string>
 0148        {
 0149            "Проверьте статус каждого выбранного заказа.",
 0150            "Проверьте заполнение обязательных реквизитов формы.",
 0151            "Проверьте настройки переходов статусов для текущей транзакции."
 0152        };
 153
 0154    var supplierEditUrl = ViewData["SupplierEditUrl"]?.ToString();
 0155    var orderHint = string.Empty;
 0156    var problemOrders = new List<string>();
 0157    var unmappedWarehouses = new List<string>();
 0158    var isUnmappedWarehouseError = errorCode == TransactionErrorCode.MixedWarehouses
 0159        && rawErrorReason.Contains("недопустимыми");
 0160    if (!string.IsNullOrWhiteSpace(rawErrorReason))
 161    {
 0162        var orderMatch = Regex.Match(rawErrorReason, @"Заказ\s+([^\s,]+)");
 0163        if (orderMatch.Success)
 164        {
 0165            orderHint = orderMatch.Groups[1].Value;
 166        }
 167
 0168        problemOrders = Regex.Matches(rawErrorReason, @"Заказ\s+([^\s,.;:]+)")
 0169            .Select(m => m.Groups[1].Value)
 0170            .Where(v => !string.IsNullOrWhiteSpace(v))
 0171            .Distinct(StringComparer.OrdinalIgnoreCase)
 0172            .Take(20)
 0173            .ToList();
 174
 0175        if (isUnmappedWarehouseError)
 176        {
 177            // Извлекаем имена складов из «отправление (склад)» — берём всё в скобках до «. Допустимые»
 0178            var beforeDopustimye = rawErrorReason.Split(". Допустимые")[0];
 0179            unmappedWarehouses = Regex.Matches(beforeDopustimye, @"\(([^)]+)\)")
 0180                .Select(m => m.Groups[1].Value.Trim())
 0181                .Where(v => !string.IsNullOrWhiteSpace(v))
 0182                .Distinct(StringComparer.OrdinalIgnoreCase)
 0183                .ToList();
 184        }
 185    }
 186}
 187
 188<div class="tx-error-panel">
 189    <div class="tx-error-panel__header">
 190        <i class="fas fa-triangle-exclamation tx-error-panel__icon"></i>
 191        <h3 class="tx-error-panel__title">Ошибка проведения транзакции</h3>
 192    </div>
 193    <div class="tx-error-panel__body">
 194        <div class="tx-error-panel__issue">
 0195            <div class="tx-error-panel__issue-title">@issueTitle</div>
 0196            @if (isUnmappedWarehouseError && unmappedWarehouses.Any())
 197            {
 198                <div class="tx-error-panel__issue-warehouse">
 199                    <i class="fas fa-warehouse"></i>
 200                    <span>
 0201                        Склад <strong>@string.Join(", ", unmappedWarehouses)</strong> не найден в настройках маппинга ск
 202                        Добавьте его в <a href="@warehouseMappingUrl">справочник маппинга складов</a>, чтобы транзакция 
 203                    </span>
 204                </div>
 205            }
 0206            else if (!string.IsNullOrWhiteSpace(rawErrorReason))
 207            {
 0208                <div class="tx-error-panel__issue-reason">@rawErrorReason</div>
 209            }
 210        </div>
 211
 212        <div class="tx-error-panel__grid">
 213            <div class="tx-error-panel__card">
 214                <div class="tx-error-panel__block-title">Что проверить и исправить</div>
 215                <ul>
 0216                    @foreach (var tip in tips)
 217                    {
 0218                        <li>@tip</li>
 219                    }
 0220                    @if (!string.IsNullOrWhiteSpace(rawConditions))
 221                    {
 0222                        @foreach (var conditionLine in rawConditions.Split("<br/>", StringSplitOptions.RemoveEmptyEntrie
 223                        {
 0224                            <li>@Html.Raw(conditionLine)</li>
 225                        }
 226                    }
 227                </ul>
 0228                @if (!string.IsNullOrWhiteSpace(orderHint))
 229                {
 230                    <div class="tx-error-panel__hint">
 0231                        Подсказка: проблемный заказ обнаружен по номеру отправления <b>@orderHint</b>.
 232                    </div>
 233                }
 234            </div>
 235            <div class="tx-error-panel__card">
 236                <div class="tx-error-panel__block-title">Что сделать сейчас</div>
 237                <div class="tx-error-panel__actions">
 0238                    @if (!string.IsNullOrWhiteSpace(editAllUrl))
 239                    {
 240                        <a class="btn btn-sm btn-warning" href="@editAllUrl" target="_blank">Изменить все</a>
 241                    }
 242                    <a class="btn btn-sm btn-outline-primary" href="@ordersUrl">К списку заказов</a>
 0243                    @if (!string.IsNullOrWhiteSpace(supplierEditUrl))
 244                    {
 245                        <a class="btn btn-sm btn-warning" href="@supplierEditUrl" target="_blank">
 246                            <i class="fas fa-pen me-1"></i>Редактировать поставщика
 247                        </a>
 248                    }
 249                </div>
 250                <details class="tx-error-panel__refs">
 251                    <summary>Служебные справочники</summary>
 252                    <div class="tx-error-panel__actions">
 253                        <a class="btn btn-sm btn-outline-secondary" href="@statusTransitionsUrl">Правила переходов стату
 254                        <a class="btn btn-sm btn-outline-secondary" href="@appStatusesUrl">Справочник статусов</a>
 255                        <a class="btn btn-sm btn-outline-secondary" href="@suppliersUrl">Справочник поставщиков</a>
 256                        <a class="btn btn-sm btn-outline-secondary" href="@warehousesUrl">Справочник складов</a>
 257                        <a class="btn btn-sm btn-outline-secondary" href="@warehouseMappingUrl">Маппинг складов</a>
 258                    </div>
 259                </details>
 260            </div>
 261        </div>
 262
 0263        @if (problemOrders.Count > 0)
 264        {
 265            <div class="tx-error-panel__orders">
 266                <div class="tx-error-panel__block-title"><i class="fas fa-list-check"></i>Проблемные заказы</div>
 267                <div class="tx-error-order-chips">
 0268                    @foreach (var order in problemOrders)
 269                    {
 270                        <button type="button"
 271                                class="tx-error-order-chip"
 0272                                data-problem-order="@order"
 273                                onclick="navigator.clipboard && navigator.clipboard.writeText('@order')">
 0274                            <i class="fas fa-exclamation-circle"></i>@order
 275                        </button>
 276                    }
 277                </div>
 278                <div class="tx-error-panel__hint">Нажмите на номер, чтобы скопировать его в буфер и быстро найти в табли
 279            </div>
 280        }
 281
 282        <div class="tx-error-panel__footer">
 283            <a class="btn btn-primary" href="@ordersUrl">
 284                <i class="fas fa-arrow-left me-1"></i>Вернуться и выбрать заказы
 285            </a>
 286        </div>
 287
 288        <div class="tx-error-panel__context">
 0289            Контекст: контроллер <b>@normalizedController</b>, действие <b>@actionName</b>.
 290        </div>
 291    </div>
 292</div>

Methods/Properties

ExecuteAsync()
GetIssueTitle()