< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_OrderedToSellerTransaction_CreateOrderedToSellerTransaction
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OrderedToSellerTransaction/CreateOrderedToSellerTransaction.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 23
Coverable lines: 23
Total lines: 361
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 44
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%812280%
<ExecuteAsync()0%506220%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OrderedToSellerTransaction/CreateOrderedToSellerTransaction.cshtml

#LineLine coverage
 1@using OzonDomains.Models.BitrixModels
 2@using OzonOrdersWeb.ViewModels.OrderViewModels
 3@using OzonOrdersWeb.Areas.Studio2.Helpers
 4
 5@model MultiplayEditOrderViewModel
 6
 7@{
 08    var viewModel = Model!;
 09    var ordersCount = Model?.Orders?.Count ?? 0;
 010    var orders = Model?.Orders ?? new List<OzonDomains.Models.Order>();
 011    ViewData["Title"] = $"Заказан продавцу ({ordersCount} заказов)";
 012    Layout = "~/Views/Shared/_Layout.cshtml";
 013    var stockData = ViewData["StockData"] as Dictionary<int, List<StockInfo>>;
 014    var transitGroups = ViewData["TransitWarehouseGroups"] as List<TransitWarehouseDisplayInfo>;
 015    var anyFound = transitGroups?.Any(g => g.FoundIn1C) ?? false;
 016    var orderInfoMapRaw = ViewData["OrderInfoMap"];
 17}
 18
 19<partial name="~/Areas/Studio2/Views/Partials/Transaction/_TransactionPageStyles.cshtml"/>
 20<script src="~/js/Studio2/Orders/CreateOrderToSupplierTransactionV2/generateInfoRow.js"></script>
 21<script>window.fillPriceFromWarehouseStock = true;</script>
 22
 23<div id="loadingSpinner" class="spinner-overlay" style="display: none;">
 24    <div class="spinner-border text-primary" role="status">
 25        <span class="sr-only"></span>
 26    </div>
 27</div>
 28
 29<div id="messageContainer" class="position-fixed top-0 end-0 p-3" style="z-index: 1050;">
 30    <div id="flashMessage" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
 31        <div class="toast-header">
 32            <strong class="me-auto">Сообщение</strong>
 33            <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
 34        </div>
 35        <div class="toast-body">
 36            <span id="flashMessageText"></span>
 37        </div>
 38    </div>
 39</div>
 40
 41<div class="modal fade" id="cartModal" tabindex="-1" aria-labelledby="cartModalLabel" aria-hidden="true">
 42    <div class="modal-dialog modal-lg modal-dialog-scrollable">
 43        <div class="modal-content rounded-3 shadow">
 44            <div class="modal-header">
 45                <h5 class="modal-title" id="cartModalLabel">Корзина</h5>
 46                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
 47            </div>
 48            <div class="modal-body" id="cartModalBody">
 49            </div>
 50            <div class="modal-footer">
 51                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
 52            </div>
 53        </div>
 54    </div>
 55</div>
 56
 057@if (orders.Count > 0)
 58{
 59    <form asp-area="Studio2" asp-controller="OrderedToSellerTransaction" asp-action="CreateOrderedToSellerTransaction"
 60          id="createOrderForm">
 61        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
 62        <input type="hidden" asp-for="RedirectPage"/>
 63        <input type="hidden" asp-for="TrackingKey"/>
 64
 065        @for (var i = 0; i < orders.Count; i++)
 66        {
 67            <input type="hidden"
 68                   name="manufacturerByOrderId[@orders[i].Id]"
 69                   value="@(orders[i].EtProducer?.Name ?? "")"/>
 70        }
 71
 072        @await Html.PartialAsync("_TransactionTable", Model)
 73
 74        <div id="otsProcessIn1CBlock" class="ms-3 mt-3" style="display:none;">
 075            @if (anyFound)
 76            {
 77                <div class="d-flex flex-wrap align-items-center gap-3">
 78                    <div class="form-check">
 79                        <input class="form-check-input" type="checkbox" id="processIn1C" name="processIn1C" value="true"
 80                        <label class="form-check-label" for="processIn1C">
 81                            <i class="fas fa-database me-1 text-primary"></i>
 82                            <strong>Провести в 1С</strong>
 83                            <span class="text-muted small ms-1">— для заказов с количеством 0 (утеря реализатором)</span
 84                        </label>
 85                    </div>
 086                    @await Html.PartialAsync("_OneCOrgSelector", Model)
 87                </div>
 88            }
 089            else if (transitGroups != null && transitGroups.Count > 0)
 90            {
 91                <div class="d-flex align-items-start gap-2 p-2 rounded"
 92                     style="background-color:#fff3cd; border:1px solid #ffc107; max-width:600px;">
 93                    <i class="fas fa-exclamation-triangle text-warning mt-1" style="font-size:1.1em;flex-shrink:0;"></i>
 94                    <div>
 95                        <div class="fw-semibold" style="color:#664d03;">Проведение в 1С недоступно</div>
 96                        <div class="small" style="color:#664d03;">
 97                            Транзитные склады
 098                            (@(string.Join(", ", transitGroups.Where(g => !g.FoundIn1C).Select(g => g.TransitWarehouse))
 99                            не настроены в WarehouseMapping или отсутствуют в 1С. Заполните поле «Транзитный склад (1С)»
 100                        </div>
 101                        <input type="hidden" name="processIn1C" value="false"/>
 102                    </div>
 103                </div>
 104            }
 105        </div>
 106
 107        <div class="tx-page-footer">
 108            <div class="ots-save-actions">
 109                <div class="input-group">
 110                    <span class="input-group-btn">
 111                        <input type="submit" value="Сохранить" class="btn btn-primary"/>
 112                    </span>
 113                </div>
 114                <a asp-area="Studio2" asp-controller="WarehouseMapping" asp-action="Index"
 115                   class="small text-muted text-decoration-none">
 116                    <i class="fas fa-link me-1"></i>Поставщики заполняются из связей складов
 117                </a>
 118            </div>
 119        </div>
 120    </form>
 121}
 122else
 123{
 0124    @await Html.PartialAsync("_TransactionErrorPanel")
 125}
 126
 127<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
 128     aria-labelledby="staticBackdropLabel" aria-hidden="true">
 129    <div class="modal-dialog">
 130        <div class="modal-content orders-modal orders-modal--primary">
 131            <div class="modal-header">
 132                <h5 class="modal-title" id="staticBackdropLabel">Создание журнала документов</h5>
 133                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
 134            </div>
 135            <div class="modal-body">
 136                <div class="d-flex justify-content-center">
 137                    <div class="spinner-border text-primary" role="status">
 138                        <span class="sr-only">.</span>
 139                    </div>
 140                </div>
 141            </div>
 142        </div>
 143    </div>
 144</div>
 145
 146<div>
 147    <a asp-action="Index" class="tx-page-back-link">← К списку заказов</a>
 148</div>
 149
 150<div class="modal fade" id="imageModal" tabindex="-1" aria-labelledby="imageModalLabel" aria-hidden="true">
 151    <div class="modal-dialog modal-dialog-centered">
 152        <div class="modal-content">
 153            <div class="modal-header">
 154                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
 155            </div>
 156            <div class="modal-body text-center">
 157                <img id="modalImage" src="" alt="Full Image" class="img-fluid rounded border">
 158            </div>
 159        </div>
 160    </div>
 161</div>
 162
 163<input type="hidden" id="deletedOrders" name="deletedOrders"/>
 164@* Скрипты таблицы нужны только когда она отрисована; на панели ошибки они падали на пустом DOM *@
 0165@if (orders.Count > 0)
 166{
 0167@await Html.PartialAsync("_TransactionScript", Model)
 168
 169<script>
 0170    var otsOrderInfoMap = @Html.Raw(System.Text.Json.JsonSerializer.Serialize(orderInfoMapRaw ?? new object()));
 171    var otsWarehouseFieldMap = { 'M2': 'm2Qty', 'M3': 'm3Qty', 'B1': 'b1Qty', 'B2': 'b2Qty' };
 172    var otsStockBadgeCache = {};
 173
 174    function insertOtsLoadingBadge(orderId, senderWarehouse) {
 175        var zasylInput = document.getElementById('orderSupplierMap_' + orderId);
 176        if (!zasylInput) return;
 177        var formGroup = zasylInput.closest('.form-group');
 178        if (!formGroup) return;
 179        var quantityInput = document.querySelector('.quantity-input-field[data-order-id="' + orderId + '"]');
 180        var originalQty = quantityInput ? parseInt(quantityInput.dataset.originalQuantity, 10) || 0 : 0;
 181        var currentQty = quantityInput ? parseInt(quantityInput.value, 10) || 0 : 0;
 182        if (currentQty !== 0 || originalQty <= 0) return;
 183        formGroup.style.display = 'none';
 184        var parent = formGroup.parentNode;
 185        var existing = parent.querySelector('.ws-ots-badge-' + orderId);
 186        if (existing) existing.remove();
 187        var badge = document.createElement('span');
 188        badge.className = 'ws-sender-badge ws-ots-badge-' + orderId;
 189        badge.style.cssText = 'background-color:#e2e3e5;color:#41464b;';
 190        var transitWarehouse = senderWarehouse ? senderWarehouse + ' (transit)' : '?';
 191        badge.innerHTML = (senderWarehouse || '?') + ' → ' + transitWarehouse + ': ' + (window.txLoadingDotsHtml ? txLoa
 192        parent.appendChild(badge);
 193    }
 194
 195    function insertOtsStockBadge(orderId, stockQty, senderWarehouse, fuzzyManufacturer) {
 196        var zasylInput = document.getElementById('orderSupplierMap_' + orderId);
 197        if (!zasylInput) return;
 198
 199        var formGroup = zasylInput.closest('.form-group');
 200        if (!formGroup) return;
 201
 202        var parent = formGroup.parentNode;
 203        var existing = parent.querySelector('.ws-ots-badge-' + orderId);
 204        if (existing) existing.remove();
 205
 206        var quantityInput = document.querySelector('.quantity-input-field[data-order-id="' + orderId + '"]');
 207        var originalQty = quantityInput ? parseInt(quantityInput.dataset.originalQuantity, 10) || 0 : 0;
 208        var currentQty = quantityInput ? parseInt(quantityInput.value, 10) || 0 : 0;
 209
 210        if (currentQty !== 0 || originalQty <= 0) return;
 211
 212        formGroup.style.display = 'none';
 213
 214        var transitWarehouse = senderWarehouse ? senderWarehouse + ' (transit)' : null;
 215        var arrow = ' → ';
 216
 217        var badge = document.createElement('span');
 218        badge.className = 'ws-sender-badge ws-ots-badge-' + orderId;
 219
 220        if (!senderWarehouse) {
 221            badge.style.cssText = 'background-color:#f8d7da;color:#842029;';
 222            badge.title = 'Склад отправителя не определён';
 223            badge.textContent = '⚠ склад не определён';
 224        } else if (stockQty === null) {
 225            badge.style.cssText = 'background-color:#e2e3e5;color:#41464b;';
 226            badge.title = 'Артикул не найден в WarehouseStock — заказ будет пропущен';
 227            badge.textContent = senderWarehouse + arrow + transitWarehouse + ': не в WS';
 228        } else if (stockQty > 0) {
 229            badge.style.cssText = 'background-color:#cfe2ff;color:#084298;';
 230            var fuzzySuffix = fuzzyManufacturer ? ' ⚠ не по производителю' : '';
 231            badge.title = fuzzyManufacturer
 232                ? 'Найдено по артикулу, производитель не совпал — проверьте вручную'
 233                : 'Перемещение ' + senderWarehouse + ' → ' + transitWarehouse + ' — будет передано в 1С';
 234            badge.textContent = senderWarehouse + arrow + transitWarehouse + ': ' + stockQty.toLocaleString('ru-RU') + '
 235        } else {
 236            badge.style.cssText = 'background-color:#fff3cd;color:#664d03;';
 237            badge.title = 'Остаток ' + senderWarehouse + ' = 0 — заказ будет пропущен';
 238            badge.textContent = senderWarehouse + arrow + transitWarehouse + ': 0 (пропуск)';
 239        }
 240
 241        parent.appendChild(badge);
 242    }
 243
 244    function removeOtsStockBadge(orderId) {
 245        var badge = document.querySelector('.ws-ots-badge-' + orderId);
 246        if (badge) badge.remove();
 247        var zasylInput = document.getElementById('orderSupplierMap_' + orderId);
 248        if (zasylInput) {
 249            var formGroup = zasylInput.closest('.form-group');
 250            if (formGroup) formGroup.style.display = '';
 251        }
 252    }
 253
 254    async function loadOtsStockBadge(orderId) {
 255        var info = otsOrderInfoMap && otsOrderInfoMap[orderId];
 256        if (!info) return;
 257
 258        if (Object.prototype.hasOwnProperty.call(otsStockBadgeCache, orderId)) {
 259            var cached = otsStockBadgeCache[orderId];
 260            insertOtsStockBadge(orderId, cached.qty, info.senderWarehouse, cached.fuzzy);
 261            return;
 262        }
 263
 264        if (!info.article) {
 265            insertOtsStockBadge(orderId, null, info.senderWarehouse, false);
 266            return;
 267        }
 268
 269        insertOtsLoadingBadge(orderId, info.senderWarehouse);
 270        try {
 271            var params = new URLSearchParams();
 272            params.set('article', info.article);
 273            var resp = await fetch('/Studio2/WarehouseStock/onec-lookup?' + params.toString());
 274            if (!resp.ok) {
 275                insertOtsStockBadge(orderId, null, info.senderWarehouse, false);
 276                return;
 277            }
 278            var data = await resp.json();
 279            var stockQty = null;
 280            if (data.found && data.stocks) {
 281                var senderLower = (info.senderWarehouse || '').trim().toLowerCase();
 282                var match = data.stocks.find(function(s) { return (s.warehouse || '').toLowerCase() === senderLower; });
 283                stockQty = match != null ? match.quantity : 0;
 284            }
 285            otsStockBadgeCache[orderId] = { qty: stockQty, fuzzy: false };
 286            insertOtsStockBadge(orderId, stockQty, info.senderWarehouse, false);
 287        } catch (e) {
 288            insertOtsStockBadge(orderId, null, info.senderWarehouse);
 289        }
 290    }
 291
 292    function updateOtsProcessIn1CBlock() {
 293        var block = document.getElementById('otsProcessIn1CBlock');
 294        if (!block) return;
 295
 296        var hasZeroQty = false;
 297        document.querySelectorAll('.quantity-input-field').forEach(function (input) {
 298            var originalQty = parseInt(input.dataset.originalQuantity, 10) || 0;
 299            var currentQty = parseInt(input.value, 10) || 0;
 300            if (originalQty > 0 && currentQty === 0) hasZeroQty = true;
 301        });
 302
 303        block.style.display = hasZeroQty ? '' : 'none';
 304    }
 305
 306    function handleOtsQuantityChange(input) {
 307        var orderId = input.dataset.orderId;
 308        var originalQty = parseInt(input.dataset.originalQuantity, 10) || 0;
 309        var currentQty = parseInt(input.value, 10) || 0;
 310
 311        if (originalQty > 0 && currentQty === 0) {
 312            loadOtsStockBadge(orderId);
 313        } else {
 314            removeOtsStockBadge(orderId);
 315        }
 316
 317        updateOtsProcessIn1CBlock();
 318    }
 319
 320    document.addEventListener('DOMContentLoaded', function () {
 321        document.querySelectorAll('.quantity-input-field').forEach(function (input) {
 322            input.addEventListener('input', function () { handleOtsQuantityChange(input); });
 323            input.addEventListener('change', function () { handleOtsQuantityChange(input); });
 324            handleOtsQuantityChange(input);
 325        });
 326    });
 327</script>
 328
 329<script>
 330    $('#createOrderForm').on('submit', function (e) {
 331        e.preventDefault();
 332
 333        if (!validateOzonCancelSelections()) {
 334            return;
 335        }
 336
 337        var formData = $(this).serialize();
 338
 0339        formData += '&userName=' + encodeURIComponent('@User.Identity?.Name')
 340            + '&comment=' + encodeURIComponent(txGetCommentFieldValue())
 0341            + '&page=' + '@(Model?.RedirectPage ?? 1)';
 342
 343        $.ajax({
 0344            url: '@Url.Action("CreateOrderedToSellerTransaction", "OrderedToSellerTransaction")',
 345            type: 'POST',
 346            data: formData,
 347            success: function (result) {
 348                if (result.redirectTo) {
 349                    window.location.href = result.redirectTo;
 350                } else {
 351                    alert('Произошла ошибка: не удалось получить URL для перенаправления.');
 352                }
 353            },
 354            error: function (xhr, status, error) {
 355                if (window.txHideSubmitOverlay) window.txHideSubmitOverlay();
 356                showFriendlyRequestError(xhr, status, error, 'Ошибка при отправке формы');
 357            }
 358        });
 359    });
 360</script>
 361}

Methods/Properties

ExecuteAsync()
<ExecuteAsync()