< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_Shared__ShippedBySupplierTransactionTable
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/Shared/_ShippedBySupplierTransactionTable.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 256
Coverable lines: 256
Total lines: 2149
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 520
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%2485024980%
Col()0%620%
<ExecuteAsync()100%210%
<ExecuteAsync()0%4260%
<ExecuteAsync()0%7280%
<ExecuteAsync()100%210%

File(s)

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

#LineLine coverage
 1@using OzonDomains.Models
 2@using OzonOrdersWeb.ViewModels.OrderViewModels
 3@using OzonOrdersWeb.Areas.Studio2.ViewHelpers
 4@model MultiplayEditOrderViewModel
 5@{
 06    var fieldMap = Model.OrderListFieldReadAccess;
 07    bool Col(string fieldName) => fieldMap == null || fieldMap.GetValueOrDefault(fieldName, true);
 08    var orders = Model.Orders;
 9}
 10
 11<link rel="stylesheet" href="~/css/Studio2/Orders/TransactionsTable.css" asp-append-version="true" />
 12
 13<div class="d-flex justify-content-between align-items-center tx-page-panel-header" style="border-top:none;">
 14    <div class="button-container">
 15        <div class="form-group col-sm-3" style="display: none;">
 16            <label for="universalField" class="col-form-label">Цена закупки:</label>
 17            <input type="text" class="form-control" id="universalField"/>
 18        </div>
 19    </div>
 20
 21    <button type="button" class="btn btn-link" data-bs-toggle="modal" data-bs-target="#exampleModal" type="submit"
 22            style="width: 18px; height: 18px; outline: none; box-shadow: none;" title="Настройка отображения таблицы">
 23        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-gear-fill"
 24             viewBox="0 0 16 16">
 25            <path
 26                d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.
 27        </svg>
 28        <span class="visually-hidden">Button</span>
 29    </button>
 30</div>
 31
 32<div class="tx-transaction-page">
 33<div class="table-container table-edge-flush">
 34<table class="table transaction-table" id="shipmentTable">
 35    <colgroup id="tableColgroup"></colgroup>
 36    <thead>
 37    <tr>
 038        @if (Col("ShipmentNumber"))
 39        {
 40            <th id="thShipmentNumber" data-column="shipmentNumber">
 41                <small>№/Номер заказа &nbsp;</small>
 42                <input id="shipmentNumberFilter" class="form-control form-control-sm" readonly/>
 43            </th>
 44        }
 45        <th data-column="client">
 046            @if (Col("OzonClient"))
 47            {
 48                <div id="thOzonClient">
 49                    <small>Клиент &nbsp; </small>
 50                    <input id="ozonClientFilterInput" class="form-control form-control-sm" autocomplete="off" readonly/>
 51                </div>
 52            }
 053            @if (Col("DeliveryCity"))
 54            {
 55                <div id="thDeliveryCity" class="text-muted" title="Город доставки">
 56                    <small>Город. &nbsp;</small>
 57                    <input id="deliveryCityFilter" class="form-control form-control-sm" readonly/>
 58                </div>
 59            }
 60        </th>
 61        <th data-column="dates">
 062            @if (Col("ProcessingDate"))
 63            {
 64                <div id="thProcessingDate" title="Принят в обработку">
 65                    <small>Принят. &nbsp;</small>
 66                    <input id="processingDateFilter" class="form-control form-control-sm" type="date" readonly/>
 67                </div>
 68            }
 069            @if (Col("ShippingDate"))
 70            {
 71                <div id="thShippingDate" class="text-muted" title="Дата отгрузки">
 72                    <small>Дата отгр. &nbsp;</small>
 73                    <input id="shippingDateFilter" class="form-control form-control-sm" type="date" readonly/>
 74                </div>
 75            }
 76        </th>
 77
 78        <th data-column="period">
 079            @if (Col("DeliveryPeriod"))
 80            {
 81                <div id="thDeliveryPeriod" title="Срок доставки">
 82                    <small>Срок. &nbsp;</small>
 83                    <input id="deliveryPeriodInput" class="form-control form-control-sm" type="text"
 84                           placeholder="1 д. 1 ч." readonly/>
 85                </div>
 86            }
 087            @if (Col("DeliveryPeriod"))
 88            {
 89                <div id="thDeliveryPeriod" class="text-muted" title="Осталось времени">
 90                    <small>Остал. &nbsp;</small>
 91                    <input id="timeLeftDayInput" class="form-control form-control-sm" type="number" placeholder="1 д."
 92                           readonly/>
 93                </div>
 94            }
 95        </th>
 96
 97        <th class="orders-product-col" data-column="productInfo">
 98            <div class="two-row-cell w-100">
 99                <div class="cell-row orders-product-head-row1">
 100                    <div id="thArticle" class="orders-product-pair">
 101                        <small>Key</small>
 102                        <input id="articleFilter" type="text" class="form-control form-control-sm" readonly/>
 103                    </div>
 104                    <div id="thManufacturer" class="orders-product-pair orders-product-pair-center">
 105                        <small>Производитель</small>
 106                        <input id="manufacturerFilter" type="text" class="form-control form-control-sm" readonly/>
 107                    </div>
 108                    <div id="thArticle2" class="orders-product-pair orders-product-pair-end">
 109                        <small>Код товара</small>
 110                        <input id="articleFilter2" type="text" class="form-control form-control-sm" readonly/>
 111                    </div>
 112                </div>
 113                <div id="thProductName" class="cell-row text-muted">
 114                    <small>Наименование товара</small>
 115                    <input id="productNameFilter" type="text" class="form-control form-control-sm" readonly/>
 116                </div>
 117            </div>
 118        </th>
 119
 120        <th class="permanent-col actions-col-head" data-column="actionsCol">
 121        </th>
 122
 123        <th class="status-column-head" data-column="status">
 0124            @if (Col("ClientStatus"))
 125            {
 126                <div id="thStatusOzon">
 127                    <small>Статус клиента &nbsp;</small>
 128                    <input id="statusFilter" class="form-control form-control-sm statusFilter" autocomplete="off"
 129                           readonly/>
 130                </div>
 131            }
 0132            @if (Col("AppStatus"))
 133            {
 134                <div id="thStatus" class="text-muted">
 135                    <small>Статус &nbsp;</small>
 136                    <input id="appStatusFilterInput" class="form-control form-control-sm" autocomplete="off" readonly/>
 137                </div>
 138            }
 139        </th>
 140
 141        <th data-column="warehouse">
 0142            @if (Col("ShipmentWarehouse"))
 143            {
 144                <div id="thShipmentWarehouse">
 145                    <small>Склад отгрузки &nbsp;</small>
 146                    <input id="shipmentWarehouseFilter" class="form-control form-control-sm" autocomplete="off"
 147                           readonly/>
 148                </div>
 149            }
 0150            @if (Col("DeliveryPeriod"))
 151            {
 152                <div id="thDeliveryPeriod">
 153                    <small>Дата изм. статуса</small>
 154                    <input id="shipmentWarehouseFilter" class="form-control form-control-sm" autocomplete="off"
 155                           readonly/>
 156                </div>
 157            }
 158        </th>
 159        <th data-column="countryGtd">
 160            <div id="thCountryGtd">
 161                <small>Страна роисх.</small>
 162                <input class="form-control form-control-sm" readonly/>
 163            </div>
 164            <div class="text-muted" style="margin-top: 5px;">
 165                <small>ГТД</small>
 166                <input class="form-control form-control-sm" readonly/>
 167            </div>
 168        </th>
 169        <th data-column="supplier">
 0170            @if (Col("Supplier"))
 171            {
 172                <div id="thSupplier">
 173                    <small>Поставщик &nbsp;</small>
 174                    <select class="form-control form-control-sm universalSelect custom-select-init" id="universalSelect"
 175                            onchange="handleSelectChange(this)">
 176                        <option value="">Выберите значение</option>
 0177                        @foreach (var supplier in Model.Suppliers)
 178                        {
 0179                            <option value="@supplier.Id" data-currency-code="@supplier.CurrencyCode"
 0180                                    data-cost-factor="@supplier.CostFactor">
 0181                                @supplier.Name - @supplier.CurrencyCode
 182                            </option>
 183                        }
 184
 0185                        <option value="create" class="link-option" data-url="@Url.Action("Create", "Supplier")">Создать
 186                            поставщика
 187                        </option>
 188                    </select>
 189                </div>
 190
 191                <script>
 192                    function handleSelectChange(selectElement) {
 193                        if (selectElement.value === "create") {
 0194                            window.location.href = '@Url.Action("Create", "Supplier")';
 195                        } else {
 196                            var selectedOption = selectElement.options[selectElement.selectedIndex];
 197                            var supplierId = selectedOption.value;
 198                            var currencyCode = selectedOption.getAttribute('data-currency-code');
 199                            var costFactor = selectedOption.getAttribute('data-cost-factor');
 200
 201                            document.querySelectorAll('.supplier-select').forEach(function (supplierSelect) {
 202                                supplierSelect.value = supplierId;
 203                                supplierSelect.dispatchEvent(new Event('change'));
 204                            });
 205
 206                            document.querySelectorAll('.supplier-select').forEach(function (supplierSelect) {
 207                                var relatedCurrencyCodeSpan = supplierSelect.closest('td').querySelector('.currency-code
 208                                if (relatedCurrencyCodeSpan) {
 209                                    relatedCurrencyCodeSpan.textContent = currencyCode;
 210                                }
 211                            });
 212                        }
 213                    }
 214                </script>
 215            }
 0216            @if (Col("SupplierOrderNumber"))
 217            {
 218                <div id="thOrderNumberToSupplierSort" class="text-muted" title="Номер заказа поставщику">
 219                    <small>Номер зак. п. &nbsp;</small>
 220                    <input type="text" class="form-control form-control-sm universalOrderNumberToSupplie"
 221                           id="universalOrderNumberToSupplier"/>
 222                </div>
 223            }
 224        </th>
 225        <th data-column="category">
 0226            @if (Col("Category"))
 227            {
 228                <div id="thCategory">
 229                    <small>Категория &nbsp;</small>
 230                    <input id="commercialCategoryFilter" class="form-control form-control-sm" readonly/>
 231                </div>
 232            }
 0233            @if (Col("VolumeWeight"))
 234            {
 235                <div id="thVolume" class="text-muted">
 236                    <small>Вес V &nbsp;</small>
 237                    <input id="volumetricWeightFilter" class="form-control form-control-sm" readonly/>
 238                </div>
 239            }
 240        </th>
 241        <th data-column="sitePrice">
 0242            @if (Col("SitePrice"))
 243            {
 244                <div id="thPurchasePrice" title="Цена сайта">
 245                    <small>Цена с. &nbsp;</small>
 246                    <input id="currentPriceWithDiscountFilter" class="form-control form-control-sm" readonly/>
 247                </div>
 248            }
 0249            @if (Col("Quantity"))
 250            {
 251                <div id="thQuantity" class="text-muted" title="Количество">
 252                    <small>Кол. &nbsp;</small>
 253                    <input id="quantityFilter" class="form-control form-control-sm" readonly/>
 254                </div>
 255            }
 256        </th>
 257        <th data-column="price">
 0258            @if (Col("Price"))
 259            {
 260                <div id="thPrice">
 261                    <small>Цена &nbsp;</small>
 262                    <input id="priceFilter" class="form-control form-control-sm" readonly/>
 263                </div>
 264            }
 265
 0266            @if (Col("ShipmentTotal"))
 267            {
 268                <div id="thShipmentAmount" class="text-muted" title="Сумма отправления">
 269                    <small>Сумма о. &nbsp;</small>
 270                    <input id="shipmentAmountFilter" class="form-control form-control-sm" readonly/>
 271                </div>
 272            }
 273        </th>
 274
 275        <th data-column="purchasePrice">
 0276            @if (Col("PurchasePrice"))
 277            {
 278                <div id="thCurrentPrice" title="Цена закупки">
 279                    <small>Цена заку. &nbsp;</small>
 280                    <input id="purchasePriceFilter" class="form-control form-control-sm" readonly/>
 281                </div>
 282            }
 0283            @if (Col("Cost"))
 284            {
 285                <div id="thCostPriceсе" class="text-muted" title="Себестоимость">
 286                    <small>Себест. &nbsp;</small>
 287                    <input id="costPriceFilter" class="form-control form-control-sm" readonly/>
 288                </div>
 289            }
 290        </th>
 0291        @if (Col("OzonCommission"))
 292        {
 293            <th id="thOzonCommission" class="tx-metric-col" data-column="commission" title="Комиссия ОЗОН">
 294                <div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
 295                    <div>
 296                        <small>Комис. &nbsp;</small>
 297                    </div>
 298                    <div style="text-align: center; font-size: 10px;" class="text-muted">
 299                        <div><small>min</small></div>
 300                        <div><small>max</small></div>
 301                    </div>
 302                </div>
 303                <input id="ozonCommissionFilter" class="form-control form-control-sm" readonly/>
 304            </th>
 305        }
 0306        @if (Col("Profit"))
 307        {
 308            <th id="thProfit" class="tx-metric-col" data-column="profit" title="Прибыль">
 309                <div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
 310                    <div>
 311                        <small>Приб. &nbsp;</small>
 312                    </div>
 313                    <div style="text-align: center; font-size: 10px;" class="text-muted">
 314                        <div><small>min</small></div>
 315                        <div><small>max</small></div>
 316                    </div>
 317                </div>
 318                <input id="profitFilter" class="form-control form-control-sm" readonly/>
 319            </th>
 320        }
 0321        @if (Col("MarkupPercent"))
 322        {
 323            <th id="thDiscount" class="tx-metric-col" data-column="markup" title="Наценка %">
 324                <div style="display: flex; flex-direction: column; align-items: center; justify-content: center;">
 325                    <div>
 326                        <small>Нацен.% &nbsp;</small>
 327                    </div>
 328                    <div style="text-align: center; font-size: 10px;" class="text-muted">
 329                        <div><small>min</small></div>
 330                        <div><small>max</small></div>
 331                    </div>
 332                </div>
 333                <input id="discountFilter" class="form-control form-control-sm" readonly/>
 334            </th>
 335        }
 336    </tr>
 337
 338    </thead>
 339    <tbody>
 340
 341    @{
 0342        int? previousShipmentId = null;
 0343        var shipmentGroups = new Dictionary<int, int>();
 0344        foreach (var o in Model.Orders.Where(o => o?.ShipmentId != null))
 345        {
 0346            var sid = o!.ShipmentId!.Value;
 0347            shipmentGroups[sid] = shipmentGroups.GetValueOrDefault(sid) + 1;
 348        }
 349    }
 350
 0351    @for (int i = 0; i < orders.Count; i++)
 352    {
 0353        if (orders[i] is not Order order)
 354        {
 355            continue;
 356        }
 0357        bool isFirstInGroup = false;
 0358        bool isInGroup = false;
 359
 0360        if (order.ShipmentId is int shipmentId)
 361        {
 0362            var groupSize = shipmentGroups.GetValueOrDefault(shipmentId, 1);
 0363            isInGroup = groupSize > 1;
 0364            isFirstInGroup = isInGroup && shipmentId != previousShipmentId;
 0365            previousShipmentId = shipmentId;
 366        }
 367        else
 368        {
 0369            previousShipmentId = null;
 370        }
 371
 0372        string rowClass = "custom-white";
 0373        if ((order.AppStatus?.Name == "Отменен" && (order.ClientStatus?.Name == "Отменён" || order.ClientStatus == null)
 0374            order.ClientStatus?.Name is "Отменен" or "Отменён")
 375        {
 0376            rowClass = "table-danger";
 377        }
 0378        else if (order.IsReturnable == true)
 379        {
 0380            rowClass = "custom-red";
 381        }
 382        else
 383        {
 0384            rowClass = order.AppStatus?.Name switch
 0385            {
 0386                "Заказан поставщику" => "table-success",
 0387                "Отгружен поставщиком" => "table-info",
 0388                "Отгружен реализатору" => "table-warning",
 0389                "Заказан реализатору" => "table-secondary",
 0390                _ => rowClass
 0391            };
 392        }
 393
 0394        if (isFirstInGroup)
 395        {
 0396            rowClass += " shipment-group-first";
 397        }
 0398        else if (isInGroup && !isFirstInGroup)
 399        {
 0400            rowClass += " shipment-group-continuation";
 401        }
 402
 403        <tr id="orderRow_@Model.Orders[i].Id" class="@rowClass transaction-order-row"
 0404            data-original-row-class="@rowClass"
 0405            data-barcode="@(Model.Orders[i].ProductInfo?.Barcode ?? "")">
 406            <div class="form-group" style="display: none">
 407                <label asp-for="Orders[i].Id" class="control-label"></label><span
 408                    style="margin-left: 10px; color: gray;">/ </span>
 409                <input asp-for="Orders[i].Id" class="form-control"/>
 410                <span asp-validation-for="Orders[i].Id" class="text-danger"></span>
 411            </div>
 412            <div class="form-group" style="display: none">
 413                <label asp-for="Orders[i].Key" class="control-label"></label><span
 414                    style="margin-left: 10px; color: gray;">/ </span>
 415                <input asp-for="Orders[i].Key" class="form-control"/>
 416                <span asp-validation-for="Orders[i].Key" class="text-danger"></span>
 417            </div>
 418            <div class="form-group" style="display: none">
 419                <label asp-for="Orders[i].ShipmentNumber" class="control-label"></label><span
 420                    style="margin-left: 10px; color: gray;">/ </span>
 421                <input asp-for="Orders[i].ShipmentNumber" class="form-control"/>
 422                <span asp-validation-for="Orders[i].ShipmentNumber" class="text-danger"></span>
 423            </div>
 424            <div class="form-group" style="display: none">
 425                <label asp-for="Orders[i].OzonClient" class="control-label"></label><span
 426                    style="margin-left: 10px; color: gray;">/ </span>
 427                <input asp-for="Orders[i].OzonClient" class="form-control"/>
 428                <span asp-validation-for="Orders[i].OzonClient" class="text-danger"></span>
 429            </div>
 430            <div class="form-group" style="display: none">
 431                <label asp-for="Orders[i].ProcessingDate" class="control-label"></label><span
 432                    style="margin-left: 10px; color: gray;">/ </span>
 433                <input asp-for="Orders[i].ProcessingDate" class="form-control"/>
 434                <span asp-validation-for="Orders[i].ProcessingDate" class="text-danger"></span>
 435            </div>
 436            <div class="form-group" style="display: none">
 437                <label asp-for="Orders[i].ShippingDate" class="control-label"></label><span
 438                    style="margin-left: 10px; color: gray;">/ </span>
 439                <input asp-for="Orders[i].ShippingDate" class="form-control"/>
 440                <span asp-validation-for="Orders[i].ShippingDate" class="text-danger"></span>
 441            </div>
 442            <div class="form-group" style="display: none">
 443                <label asp-for="Orders[i].ClientStatusId" class="control-label"></label><span
 444                    style="margin-left: 10px; color: gray;">/ </span>
 445                <input asp-for="Orders[i].ClientStatusId" class="form-control"/>
 446                <span asp-validation-for="Orders[i].ClientStatusId" class="text-danger"></span>
 447            </div>
 448            <div class="form-group" style="display: none">
 449                <label asp-for="Orders[i].ProductName" class="control-label"></label><span
 450                    style="margin-left: 10px; color: gray;">/ </span>
 451                <input asp-for="Orders[i].ProductName" class="form-control"/>
 452                <span asp-validation-for="Orders[i].ProductName" class="text-danger"></span>
 453            </div>
 454            <div class="form-group" style="display: none">
 455                <label asp-for="Orders[i].ProductKey" class="control-label"></label><span
 456                    style="margin-left: 10px; color: gray;">/ </span>
 457                <input asp-for="Orders[i].ProductKey" class="form-control"/>
 458                <span asp-validation-for="Orders[i].ProductKey" class="text-danger"></span>
 459            </div>
 460            <div class="form-group" style="display: none">
 461                <label asp-for="Orders[i].Quantity" class="control-label"></label><span
 462                    style="margin-left: 10px; color: gray;">/ </span>
 463                <input asp-for="Orders[i].Quantity" class="form-control"/>
 464                <span asp-validation-for="Orders[i].Quantity" class="text-danger"></span>
 465            </div>
 466            <div class="form-group" style="display: none">
 467                <label asp-for="Orders[i].ShipmentAmount" class="control-label"></label><span
 468                    style="margin-left: 10px; color: gray;">/ </span>
 469                <input asp-for="Orders[i].ShipmentAmount" class="form-control"/>
 470                <span asp-validation-for="Orders[i].ShipmentAmount" class="text-danger"></span>
 471            </div>
 472            <div class="form-group" style="display: none">
 473                <label asp-for="Orders[i].Price" class="control-label"></label><span
 474                    style="margin-left: 10px; color: gray;">/ </span>
 475                <input asp-for="Orders[i].Price" class="form-control"/>
 476                <span asp-validation-for="Orders[i].Price" class="text-danger"></span>
 477            </div>
 478            <div class="form-group" style="display: none">
 479                <label asp-for="Orders[i].MaxProfit" class="control-label"></label><span
 480                    style="margin-left: 10px; color: gray;">/ </span>
 481                <input asp-for="Orders[i].MaxProfit" class="form-control"/>
 482                <span asp-validation-for="Orders[i].MaxProfit" class="text-danger"></span>
 483            </div>
 484            <div class="form-group" style="display: none">
 485                <label asp-for="Orders[i].MinDiscount" class="control-label"></label><span
 486                    style="margin-left: 10px; color: gray;">/ </span>
 487                <input asp-for="Orders[i].MinDiscount" class="form-control"/>
 488                <span asp-validation-for="Orders[i].MinDiscount" class="text-danger"></span>
 489            </div>
 490            <div class="form-group" style="display: none">
 491                <label asp-for="Orders[i].DeliveryCity" class="control-label"></label><span
 492                    style="margin-left: 10px; color: gray;">/ </span>
 493                <input asp-for="Orders[i].DeliveryCity" class="form-control"/>
 494                <span asp-validation-for="Orders[i].DeliveryCity" class="text-danger"></span>
 495            </div>
 496
 497            <div class="form-group" style="display: none">
 498                <label asp-for="Orders[i].UpdatedBy" class="control-label"></label><span
 499                    style="margin-left: 10px; color: gray;">/ </span>
 0500                <input asp-for="Orders[i].UpdatedBy" class="form-control" value="@Model.Orders[i].UpdatedBy"/>
 501                <span asp-validation-for="Orders[i].UpdatedBy" class="text-danger"></span>
 502            </div>
 503
 504            <div class="form-group" style="display: none">
 505                <label asp-for="Orders[i].TimeLeftDay" class="control-label"></label><span
 506                    style="margin-left: 10px; color: gray;">/ </span>
 0507                <input asp-for="Orders[i].TimeLeftDay" class="form-control" value="@Model.Orders[i].TimeLeftDay"/>
 508                <span asp-validation-for="Orders[i].TimeLeftDay" class="text-danger"></span>
 509            </div>
 510
 511            <div class="form-group" style="display: none">
 512                <label asp-for="Orders[i].FormattedTimeLeftDay" class="control-label"></label><span
 513                    style="margin-left: 10px; color: gray;">/ </span>
 514                <input asp-for="Orders[i].FormattedTimeLeftDay" class="form-control"
 0515                       value="@Model.Orders[i].FormattedTimeLeftDay"/>
 516                <span asp-validation-for="Orders[i].FormattedTimeLeftDay" class="text-danger"></span>
 517            </div>
 518
 519            <div class="form-group" style="display: none">
 520                <label asp-for="Orders[i].OzonClient.Id" class="control-label"></label><span
 521                    style="margin-left: 10px; color: gray;">/ </span>
 0522                <input asp-for="Orders[i].OzonClient.Id" class="form-control" value="@Model.Orders[i].OzonClient?.Id"/>
 523                <span asp-validation-for="Orders[i].OzonClient.Id" class="text-danger"></span>
 524            </div>
 525            <div class="form-group" style="display: none">
 526                <label asp-for="Orders[i].Article" class="control-label"></label><span
 527                    style="margin-left: 10px; color: gray;">/ </span>
 0528                <input asp-for="Orders[i].Article" class="form-control" value="@Model.Orders[i].Article"/>
 529                <span asp-validation-for="Orders[i].Article" class="text-danger"></span>
 530            </div>
 531            <div class="form-group" style="display: none">
 532                <label asp-for="Orders[i].ProductInfo.Id" class="control-label"></label><span
 533                    style="margin-left: 10px; color: gray;">/ </span>
 0534                <input asp-for="Orders[i].ProductInfo.Id" class="form-control" value="@Model.Orders[i].ProductInfo?.Id"/
 535                <span asp-validation-for="Orders[i].ProductInfo.Id" class="text-danger"></span>
 536            </div>
 537
 538            <input type="hidden" asp-for="Orders[i].ProductInfoId"/>
 0539            @if (Col("ShipmentNumber"))
 540            {
 541                <td data-column="shipmentNumber">
 542                    <div class="d-flex align-items-center">
 543                    <span class="ml-2">
 544                        <b class="row-number"></b>
 545                        <br/>
 0546                        @if (isInGroup && !isFirstInGroup)
 547                        {
 548                            <span class="shipment-group-indicator"
 549                                  title="Часть отправления @order.ShipmentId">
 550                                <i class="fas fa-level-up-alt fa-rotate-90 fa-lg"></i>
 551                            </span>
 552                        }
 553                        else
 554                        {
 0555                            @Html.DisplayFor(modelItem => Model.Orders[i].ShipmentNumber)
 556                        }
 0557                        @if (!(isInGroup && !isFirstInGroup)
 0558                             && Model.Orders[i].ShipmentNumber is { } shipmentNum
 0559                             && shipmentNum != ""
 0560                             && Model.UniqueNumbers.TryGetValue(shipmentNum.Split('-')[0], out var shipmentCount)
 0561                             && shipmentCount != 1)
 562                        {
 0563                            <a href="#">(@shipmentCount)</a>
 564                        }
 565                    </span>
 566                    </div>
 567                    <div class="text-muted d-flex" style="white-space: nowrap;">
 568                        @{
 0569                            string? delivery = Model.Orders[i].Delivery?.Provider?.Name;
 570
 0571                            if (!string.IsNullOrEmpty(delivery) && delivery.Length > 20)
 572                            {
 0573                                delivery = delivery.Substring(0, 20) + "...";
 574                            }
 575
 0576                            <p title="@Model.Orders[i].Delivery?.Name">@delivery</p>
 577                        }
 578                    </div>
 579                </td>
 580            }
 581            <td data-column="client">
 0582                @if (Col("OzonClient"))
 583                {
 584                    <div title="@Model.Orders[i].OzonClient">
 0585                        @if (Model.Orders[i].OzonClient != null)
 586                        {
 0587                            string? ozonClient = Model.Orders[i].OzonClient?.Name;
 0588                            if (!string.IsNullOrEmpty(ozonClient) && ozonClient.Length > 18)
 589                            {
 0590                                ozonClient = ozonClient.Substring(0, 18) + "...";
 591                            }
 592
 0593                            @ozonClient
 594                        }
 595                    </div>
 596                }
 0597                @if (Col("DeliveryCity"))
 598                {
 0599                    @if (Model.Orders[i].DeliveryCity != null && Model.Orders[i].DeliveryCity != "")
 600                    {
 601                        <div class="text-muted d-flex align-items-center" style="white-space: nowrap;"
 602                             title="@Model.Orders[i].DeliveryCity">
 603                            @{
 0604                                string? deliveryCity = Model.Orders[i].DeliveryCity;
 0605                                if (!string.IsNullOrEmpty(deliveryCity) && deliveryCity.Length > 11)
 606                                {
 0607                                    deliveryCity = deliveryCity.Substring(0, 11) + "...";
 608                                }
 609
 0610                                @deliveryCity
 611                            }
 0612                            @if (Model.Orders[i].DeliveryCity is { } dcKey && Model.UniqueDeliveryCitys.ContainsKey(dcKe
 613                            {
 614                                <a href="#"
 0615                                   style="margin-left: 2px;">(@Model.UniqueDeliveryCitys[dcKey])</a>
 616                            }
 617                        </div>
 618                    }
 619                }
 0620                @if (!string.IsNullOrEmpty(Model.Orders[i].TrackingNumber))
 621                {
 622                    <div class="text-muted" style="white-space: nowrap;" title="@Model.Orders[i].TrackingNumber">
 0623                        <small>@Model.Orders[i].TrackingNumber</small>
 624                    </div>
 625                }
 626            </td>
 627
 628            <td data-column="dates">
 0629                @if (Col("ProcessingDate"))
 630                {
 631                    <div id="td2ProcessingDate"
 632                         title="@Html.DisplayFor(modelItem => Model.Orders[i].FullFormattedProcessingDate)">
 0633                        @Html.DisplayFor(modelItem => Model.Orders[i].FormattedProcessingDate)
 634                    </div>
 635                }
 636
 0637                @if (Col("ShippingDate"))
 638                {
 639                    <div class="text-muted"
 640                         title="@Html.DisplayFor(modelItem => Model.Orders[i].FullFormattedShippingDate)">
 0641                        @Html.DisplayFor(modelItem => Model.Orders[i].FormattedShippingDate)
 642                    </div>
 643                }
 644            </td>
 645
 646            <td data-column="period">
 0647                @if (Col("DeliveryPeriod"))
 648                {
 649                    <div style="white-space: nowrap; text-align: right;">
 650                        <div
 0651                            title="@Html.DisplayFor(modelItem => Model.Orders[i].FormattedDeliveryDay) @Html.DisplayFor(
 652                    </div>
 653                }
 0654                @if (Col("DeliveryPeriod"))
 655                {
 656                    <div style="white-space: nowrap; text-align: right;" class="text-muted">
 0657                        @Html.DisplayFor(modelItem => Model.Orders[i].FormattedTimeLeftDay)
 658                    </div>
 659                }
 660            </td>
 661
 662            <td class="orders-product-col" data-column="productInfo">
 663                <div class="container">
 664                    <div class="row mb-0 justify-content-between">
 0665                        @if (Col("ProductKey"))
 666                        {
 667                            <div id="thArticle" class="col-md-4 d-flex align-items-center mb-1"
 668                                 style="white-space: nowrap;" title="@Model.Orders[i].ProductKey">
 669                                @{
 0670                                    string? productKey = Model.Orders[i].ProductKey;
 0671                                    string? displayText = productKey;
 672
 0673                                    if (!string.IsNullOrEmpty(productKey))
 674                                    {
 675                                        // Регулярное выражение для поиска [число] в конце строки
 0676                                        var match = System.Text.RegularExpressions.Regex.Match(productKey, @"\[(\d+)\]$"
 677
 0678                                        if (match.Success)
 679                                        {
 680                                            // Разделяем строку на основную часть и числовую часть в скобках
 0681                                            string mainPart = productKey.Substring(0, match.Index);
 0682                                            string numberPart = match.Value; // [число]
 683
 684                                            // Обрезаем основную часть если нужно
 0685                                            if (mainPart.Length > 17)
 686                                            {
 0687                                                mainPart = mainPart.Substring(0, 17) + "...";
 688                                            }
 689
 690                                            // Формируем текст с подсветкой
 0691                                            displayText = $"{mainPart}<span class='text-success fw-bold product-key-mult
 692                                        }
 693                                        else
 694                                        {
 695                                            // Старая логика обрезки если нет [числа] в конце
 0696                                            if (productKey.Length > 17)
 697                                            {
 0698                                                displayText = productKey.Substring(0, 17) + "...";
 699                                            }
 700                                        }
 701                                    }
 702                                }
 703
 704                                <span class="custom-product-link">
 0705                                    @Html.Raw(displayText)
 706                                </span>
 707
 708                                <button type="button" class="btn-link p-0 hidden-info-icon"
 709                                        style="background-color: inherit; width: 20px; height: 20px; display: none;"
 0710                                        data-order-id="@Model.Orders[i].Id">
 711                                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor"
 712                                         class="bi bi-check" viewBox="0 0 16 16">
 713                                        <path
 714                                            d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 
 715                                    </svg>
 716                                </button>
 717                            </div>
 718                        }
 0719                        @if (Col("Manufacturer"))
 720                        {
 721                            <div id="thManufacturer" class="col-md-4 d-flex flex-column mb-1 nowrap text-center">
 0722                                @(Model.Orders[i].EtProducer?.Name ?? "")
 723                            </div>
 724                        }
 0725                        @if (Col("Article"))
 726                        {
 727                            <div id="thArticle2_@Model.Orders[i].Id"
 728                                 class="col-md-4 d-flex flex-column mb-1 nowrap text-end">
 0729                                @if (Model.Orders[i].Article != null)
 730                                {
 0731                                    @Html.DisplayFor(modelItem => Model.Orders[i].Article)
 732                                }
 733                            </div>
 734                        }
 735                    </div>
 736                    <div class="row mt-0">
 0737                        @if (Col("ProductName"))
 738                        {
 739                            <div id="thProductName" class="custom-width-large d-flex flex-column text-muted">
 740                                <div>
 741                                    <div class="product-cell"
 742                                         title="@Html.DisplayFor(modelItem => Model.Orders[i].ProductName)">
 0743                                        @Html.DisplayFor(modelItem => Model.Orders[i].ProductName)
 744                                    </div>
 745                                </div>
 746                            </div>
 747                        }
 748                        <!-- Галки поставщиков (горизонтальное расположение) -->
 749                        <div style="display: flex; gap: 4px; margin-bottom: 4px; padding-left: 8px;">
 750                            <!-- Поставщик (зеленый) -->
 751                            <button type="button" class="btn-link p-0 preferred-supplier"
 752                                    style="background: none; border: none; width: 12px; height: 12px; display: none; mar
 0753                                    data-order-id="@Model.Orders[i].Id"
 754                                    title="Поставщик">
 755                                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#28a745">
 756                                    <path
 757                                        d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.
 758                                </svg>
 759                            </button>
 760
 761                            <!-- Tradesoft (зеленый) -->
 762                            <button type="button" class="btn-link p-0 preferred-tradesoft"
 763                                    style="background: none; border: none; width: 12px; height: 12px; display: none; mar
 0764                                    data-order-id="@Model.Orders[i].Id"
 765                                    title="Tradesoft">
 766                                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#28a745">
 767                                    <path
 768                                        d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.
 769                                </svg>
 770                            </button>
 771
 772                            <!-- Склад (зеленый) -->
 773                            <button type="button" class="btn-link p-0 preferred-stock"
 774                                    style="background: none; border: none; width: 12px; height: 12px; display: none; mar
 0775                                    data-order-id="@Model.Orders[i].Id"
 776                                    title="Склад">
 777                                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#28a745">
 778                                    <path
 779                                        d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.
 780                                </svg>
 781                            </button>
 782
 783                            <!-- ABCP (синий) -->
 784                            <button type="button" class="btn-link p-0 preferred-abcp"
 785                                    style="background: none; border: none; width: 12px; height: 12px; display: none; mar
 0786                                    data-order-id="@Model.Orders[i].Id"
 787                                    title="ABCP">
 788                                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#1976d2">
 789                                    <path
 790                                        d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.
 791                                </svg>
 792                            </button>
 793
 794                            <!-- AVD (голубой, text-info) -->
 795                            <button type="button" class="btn-link p-0 preferred-avd"
 796                                    style="background: none; border: none; width: 12px; height: 12px; display: none; mar
 0797                                    data-order-id="@Model.Orders[i].Id"
 798                                    title="AVD">
 799                                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="#17a2b8">
 800                                    <path
 801                                        d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.
 802                                </svg>
 803                            </button>
 804                        </div>
 805                    </div>
 806                </div>
 807            </td>
 808
 809            <td class="permanent-col actions-col-cell" data-column="actionsCol">
 810                <div class="d-flex flex-column align-items-center justify-content-center checkbox-column">
 811                    <button type="button" class="btn-link p-0 delete-order" style="width: 18px; height: 18px;"
 0812                            data-order-id="@Model.Orders[i].Id">
 813                        <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor"
 814                             class="bi bi-trash-fill" viewBox="0 0 16 16">
 815                            <path
 816                               d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 
 817                        </svg>
 818                        <span class="visually-hidden">Button</span>
 819                    </button>
 820                    <br/>
 821                    <button type="button"
 822                            class="btn-link p-0 get-full-order-info"
 823                            style="background-color: inherit; width: 18px; height: 18px;"
 0824                            data-order-id="@Model.Orders[i].Id"
 0825                            data-order-article="@Model.Orders[i].Article"
 0826                            data-order-producer-id="@Model.Orders[i].EtProducer?.Id"
 0827                            data-order-producer-name="@Model.Orders[i].EtProducer?.Name">
 828                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
 829                             class="bi bi-chevron-double-down" viewBox="0 0 16 16">
 830                            <path fill-rule="evenodd"
 831                                  d="M1.646 6.646a.5.5 0 0 1 .708 0L8 12.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0
 832                            <path fill-rule="evenodd"
 833                                  d="M1.646 2.646a.5.5 0 0 1 .708 0L8 8.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 
 834                        </svg>
 835                        <span class="visually-hidden">Info</span>
 836                    </button>
 837                </div>
 838            </td>
 839
 840            <td data-column="status">
 0841                @if (Col("ClientStatus"))
 842                {
 843                    <div class="nowrap">
 0844                        @if (Model.Orders[i].ClientStatus?.Name != null)
 845                        {
 0846                            string? status = Model.Orders[i].ClientStatus?.Name;
 0847                            if (!string.IsNullOrEmpty(status) && status.Length > 14)
 848                            {
 0849                                status = status.Substring(0, 14) + "...";
 850                            }
 851
 0852                            @status
 853                        }
 854                        else
 855                        {
 856                            <br/>
 857                        }
 858
 859                    </div>
 860                }
 861
 862                <div style="margin-top: 12px;"></div>
 863
 0864                @if (Col("AppStatus"))
 865                {
 866                    <div class="text-muted nowrap">
 867                        <select asp-for="Orders[i].AppStatusId" asp-items="@ViewBag.AppStatuses"
 868                                class="form-control form-control-sm status-select custom-select-init"
 869                                id="AppStatusId_@Model.Orders[i].Id">
 0870                            <option value="@Model.Orders[i].AppStatus?.Id">@(Model.Orders[i].AppStatus?.Name)</option>
 871                        </select>
 872                    </div>
 0873                    @if (Model.Orders[i].CartItemStatus != null)
 874                    {
 875                        <div class="text-info text-muted nowrap" style="font-size: 13px;"
 876                             title="@(Model.Orders[i].CartItemStatus?.Name)">
 877                            @{
 0878                                string? cartStatus = Model.Orders[i].CartItemStatus!.Name;
 0879                                if (!string.IsNullOrEmpty(cartStatus) && cartStatus.Length > 14)
 880                                {
 0881                                    cartStatus = cartStatus.Substring(0, 14) + "...";
 882                                }
 883                            }
 0884                            @cartStatus
 885                        </div>
 886                    }
 887                }
 888            </td>
 889
 890            <td data-column="warehouse">
 0891                @if (Col("ShipmentWarehouse"))
 892                {
 893                    <div
 894                        class="@(Model.Orders[i].UpdatedColumns is { } updatedColsWh && updatedColsWh.Contains("Shipment
 0895                        @(Model.Orders[i].ShipmentWarehouse?.Name)
 896                    </div>
 897                    <div id="bitrixStores_@Model.Orders[i].Article"></div>
 898                }
 899                <script>
 900                    getBitrixData(
 0901                        '@Model.Orders[i].Article',
 0902                        'bitrixStores_@Model.Orders[i].Article',
 0903                        'PurchasePrice_@Model.Orders[i].Id'
 904                    );
 905                </script>
 906                <div style="margin-top: 12px;"></div>
 0907                @if (Col("ShipmentWarehouse"))
 908                {
 909                    <div class="form-group">
 910                        @{
 911                            // Находим расширение с ключом "Засыл"
 0912                            var zasylValue = Model.Orders[i].OrderExtensions?
 0913                                .FirstOrDefault(e => e.Key == "Засыл")?.Value;
 914                        }
 915
 916                        <div class="position-relative">
 917                            <input type="text"
 918                                   name="orderSupplierMap[@Model.Orders[i].Id]"
 919                                   id="orderSupplierMap_@Model.Orders[i].Id"
 920                                   class="form-control form-control-sm zasyl-input combobox-input"
 921                                   placeholder="Засыл"
 922                                   value="@(zasylValue ?? string.Empty)"
 923                                   autocomplete="off"
 924                                   aria-haspopup="listbox"
 925                                   aria-expanded="false"/>
 926
 927                            <ul class="list-group combobox-menu"
 928                                id="zasylMenu_@Model.Orders[i].Id"
 929                                style="position:absolute; z-index:9999; width:100%; max-height:200px; overflow:auto; dis
 0930                                @foreach (var z in Model.ZasylValues)
 931                                {
 0932                                    <li class="list-group-item list-group-item-action combobox-item" data-value="@z"
 0933                                        role="option">@z</li>
 934                                }
 935                            </ul>
 936
 937                            <script>
 938                                document.addEventListener('DOMContentLoaded', () => {
 0939                                    new Combobox('orderSupplierMap_@Model.Orders[i].Id', 'zasylMenu_@Model.Orders[i].Id'
 940                                });
 941                            </script>
 942
 943                        </div>
 944                    </div>
 945                }
 946            </td>
 947
 948            <td data-column="countryGtd">
 949                <div class="position-relative">
 950                    <div class="form-group mb-0">
 951                        <input type="text"
 952                               name="orderCountryMap[@Model.Orders[i].Id]"
 953                               id="orderCountryMap_@Model.Orders[i].Id"
 954                               class="form-control form-control-sm combobox-input"
 955                               placeholder="Страна"
 956                               required
 957                               autocomplete="off"
 958                               aria-haspopup="listbox"
 959                               aria-expanded="false"/>
 960                    </div>
 961
 962                    <ul class="list-group combobox-menu"
 963                        id="countryMenu_@Model.Orders[i].Id"
 964                        style="position:fixed; z-index:2147483000; min-width:100%; width:max-content; max-width:900px; m
 0965                        @foreach (var country in Model.CountryValues)
 966                        {
 0967                            <li class="list-group-item list-group-item-action combobox-item" data-value="@country"
 0968                                role="option">@country</li>
 969                        }
 970                    </ul>
 971                </div>
 972
 973                <div style="margin-top: 5px;"></div>
 974
 975                <div class="text-muted">
 976                    <div class="form-group mb-0">
 977                        <input type="text"
 978                               name="orderGtdMap[@Model.Orders[i].Id]"
 979                               id="orderGtdMap_@Model.Orders[i].Id"
 980                               class="form-control form-control-sm gtd-autocomplete"
 981                               placeholder="Номер ГТД"
 982                               required
 983                               autocomplete="off"
 0984                               data-order-id="@Model.Orders[i].Id"/>
 985                    </div>
 986                </div>
 987            </td>
 988
 989            <td data-column="supplier">
 0990                @if (Col("Supplier"))
 991                {
 992                    <div class="position-relative d-inline-block d-flex">
 993                        <div class="form-group supplier-hover-area mb-0">
 994                            <select asp-for="Orders[i].SupplierId" asp-items="@ViewBag.Suppliers"
 995                                    class="form-control form-control-sm supplier-select"
 996                                    id="SupplierId_@Model.Orders[i].Id">
 997                                <option value="">Выберите поставщика</option>
 0998                                @foreach (var supplier in Model.Suppliers)
 999                                {
 01000                                    <option value="@supplier.Id"
 01001                                            data-currency-code="@supplier.CurrencyCode"
 01002                                            data-cost-factor="@supplier.CostFactor"
 01003                                            data-weight-factor="@supplier.WeightFactor"
 01004                                            data-weight-currency-code="@supplier.WeightFactorCurrencyCode"
 01005                                            data-site="@supplier.Site">
 01006                                        @supplier.Name - @supplier.CurrencyCode
 1007                                    </option>
 1008                                }
 1009                            </select>
 1010                        </div>
 1011                    </div>
 1012                }
 1013
 1014                <div style="margin-top: 5px;"></div>
 1015
 01016                @if (Col("SupplierOrderNumber"))
 1017                {
 1018                    <div class="text-muted">
 1019                        <div class="form-group">
 1020                            <input asp-for="Orders[i].OrderNumberToSupplier" type="text"
 1021                                   class="form-control form-control-sm orderNumberToSupplie-field"
 1022                                   id="OrderNumberToSupplier_@Model.Orders[i].Id"/>
 1023                            <span asp-validation-for="Orders[i].OrderNumberToSupplier" class="text-danger"
 1024                                  id="OrderNumberToSupplierValidation_@Model.Orders[i].Id"></span>
 1025                        </div>
 1026                    </div>
 1027                }
 1028            </td>
 1029
 1030            <td data-column="category">
 01031                @if (Col("Category"))
 1032                {
 1033                    <div style="display: flex; justify-content: space-between; align-items: center;">
 1034                        <div>
 01035                            @if (Model.Orders[i].ProductInfo?.CommercialCategory is { } catRaw)
 1036                            {
 01037                                string? сommercialCategory = catRaw;
 01038                                if (сommercialCategory.Length > 14)
 1039                                {
 01040                                    сommercialCategory = сommercialCategory.Substring(0, 14) + "..." + " ";
 1041                                }
 1042                                else
 1043                                {
 01044                                    сommercialCategory = сommercialCategory + " ";
 1045                                }
 1046
 01047                                @сommercialCategory
 1048                            }
 1049                        </div>
 1050
 1051                        <span style="margin-left: auto;" class="text-muted">
 01052                                        @(Model.Orders[i].ProductInfo?.VolumetricWeight)
 1053                                    </span>
 1054                    </div>
 1055                }
 1056                <div style="margin-top: 18px;"></div>
 1057
 01058                @if (Col("VolumeWeight"))
 1059                {
 1060                    <div class="text-muted cell-row product-weight-row">
 1061                        <div class="form-group d-flex align-items-center product-weight-wrap mb-0">
 1062                            <div class="form-group mb-0">
 1063                                <input asp-for="Orders[i].ProductInfo.Weight"
 1064                                       class="form-control form-control-sm product-weight-field"
 1065                                       id="ProductWeight_@Model.Orders[i].Id"
 01066                                       value="@string.Format("{0:N0}", Model.Orders[i].ProductInfo?.Weight ?? 0).Replace
 1067                                <span asp-validation-for="Orders[i].ProductInfo.Weight" class="text-danger"></span>
 1068                            </div>
 1069                            <div class="product-weight-label">
 1070                                <span>Вес кг.</span>
 1071                            </div>
 1072                        </div>
 1073                    </div>
 1074                }
 1075            </td>
 1076
 1077            <td data-column="sitePrice">
 01078                @if (Col("SitePrice"))
 1079                {
 1080                    <div style="text-align: right;">
 01081                        @Html.Raw(string.Format("{0:N0}", Model.Orders[i].ProductInfo?.CurrentPriceWithDiscount).Replace
 1082                    </div>
 1083                }
 1084                <br/>
 01085                @if (Col("Quantity"))
 1086                {
 01087                    var originalQuantity = Model.Orders[i].Quantity;
 1088                    <div class="text-muted quantity-cell"
 1089                         style="text-align: right; position: relative; margin-top: 5px;"
 1090                         id="Quantity_@Model.Orders[i].Id">
 1091                        <div style="display: flex; align-items: center; justify-content: flex-end; gap: 5px;">
 1092                            <!-- Скрытое поле для отправки значения -->
 1093                            <input asp-for="Orders[i].Quantity"
 1094                                   type="hidden"
 1095                                   class="quantity-hidden-input"
 01096                                   value="@originalQuantity"
 01097                                   data-original-quantity="@originalQuantity"
 01098                                   data-order-id="@Model.Orders[i].Id"/>
 1099
 1100                            <!-- Отображаемое значение -->
 1101                            <span class="quantity-display @(originalQuantity > 1 ? "qty-value--multi" : "")"
 1102                                  style="min-width: 25px; text-align: right; display: inline-block;"
 01103                                  data-order-id="@Model.Orders[i].Id">@originalQuantity</span>
 1104
 1105                            <!-- Кастомные стрелки -->
 1106                            <div class="quantity-arrows-wrapper"
 1107                                 style="display: flex; flex-direction: column; margin-left: 3px; gap: 2px;">
 1108                                <button type="button"
 1109                                        class="quantity-arrow-btn quantity-arrow-up"
 01110                                        data-order-id="@Model.Orders[i].Id"
 1111                                        data-action="increment"
 01112                                        data-original-quantity="@originalQuantity"
 1113                                        title="При изменении количества будет создан новый заказ с отнятым остатком и ис
 1114                                        style="background: none; border: none; padding: 0; cursor: pointer; width: 14px;
 1115                                    <svg width="10" height="6" viewBox="0 0 10 6" fill="none"
 1116                                         xmlns="http://www.w3.org/2000/svg">
 1117                                        <path d="M5 0L0 5H10L5 0Z" fill="#666"/>
 1118                                    </svg>
 1119                                </button>
 1120                                <button type="button"
 1121                                        class="quantity-arrow-btn quantity-arrow-down"
 01122                                        data-order-id="@Model.Orders[i].Id"
 1123                                        data-action="decrement"
 01124                                        data-original-quantity="@originalQuantity"
 1125                                        title="При изменении количества будет создан новый заказ с отнятым остатком и ис
 1126                                        style="background: none; border: none; padding: 0; cursor: pointer; width: 14px;
 1127                                    <svg width="10" height="6" viewBox="0 0 10 6" fill="none"
 1128                                         xmlns="http://www.w3.org/2000/svg">
 1129                                        <path d="M5 6L0 1H10L5 6Z" fill="#666"/>
 1130                                    </svg>
 1131                                </button>
 1132                            </div>
 1133                            <span asp-validation-for="Orders[i].Quantity" class="text-danger"></span>
 1134                        </div>
 1135                    </div>
 1136                }
 1137            </td>
 1138
 1139            <td data-column="price">
 01140                @if (Col("Price"))
 1141                {
 1142                    <div style="text-align: right;" id="Price_@Model.Orders[i].Id">
 01143                        <span id="CurrentPriceWithDiscount_@Model.Orders[i].Id" class="d-none">@Model.Orders[i].ProductI
 01144                        @OrderCellFormat.Money(Model.Orders[i].Price)
 1145                    </div>
 1146                }
 1147                <br/>
 01148                @if (Col("ShipmentTotal"))
 1149                {
 1150                    <div class="text-muted" style="text-align: right;" id="shipmentAmount_@i">
 01151                        @OrderCellFormat.Money(Model.Orders[i].ShipmentAmount)
 1152                    </div>
 1153                }
 1154            </td>
 1155
 1156            <td data-column="purchasePrice">
 1157                <div class="two-row-cell purchase-price-cell">
 1158                    <div class="cell-row purchase-price-top-row">
 01159                        @if (Col("PurchasePrice"))
 1160                        {
 01161                            var price = Model.Orders[i].OriginalPurchasePrice ?? Model.Orders[i].PurchasePrice;
 1162                            <input asp-for="Orders[i].OriginalPurchasePrice"
 1163                                   type="text"
 1164                                   class="form-control form-control-sm purchase-price-field"
 1165                                   id="PurchasePrice_@Model.Orders[i].Id"
 01166                                   data-order-id="@Model.Orders[i].Id"
 01167                                   value="@(price != 0 ? price : "")"
 1168                                   oninput="this.value = this.value.replace(',', '.').replace(/[^0-9.]/g, '').replace(/(
 1169                            <input type="hidden" asp-for="Orders[i].PurchasePrice"
 1170                                   id="PurchasePriceHidden_@Model.Orders[i].Id"/>
 1171                            <span class="purchase-price-rub visually-hidden"
 1172                                  id="PurchasePriceRub_@Model.Orders[i].Id"
 1173                                  aria-hidden="true"></span>
 1174                        }
 1175                    </div>
 1176
 1177                    <div class="cell-row text-muted purchase-price-bottom-row">
 01178                        @if (Col("Cost"))
 1179                        {
 1180                            <span id="CostPrice_@Model.Orders[i].Id"></span>
 1181                        }
 1182                    </div>
 1183                </div>
 1184            </td>
 1185
 1186
 1187
 01188            @if (Col("OzonCommission"))
 1189            {
 01190                @if (Model.Orders[i].MinOzonCommission == 0 && Model.Orders[i].MaxOzonCommission == 0)
 1191                {
 1192                    <td class="tx-metric-col" data-column="commission" style="text-align: right;">
 1193                        <div class="form-group d-flex align-items-center justify-content-end mb-2">
 1194                            <div class="flex-grow-1">
 1195                                <input asp-for="Orders[i].MinOzonCommission"
 1196                                       class="form-control form-control-sm ozon-commission-field"
 1197                                       id="MinOzonCommission_@Model.Orders[i].Id" style="text-align: right;"/>
 1198                                <span asp-validation-for="Orders[i].MinOzonCommission" class="text-danger"
 1199                                      id="MinOzonCommissionValidation_@Model.Orders[i].Id"></span>
 1200                            </div>
 1201                            <div style="margin-left: auto;">
 1202                                <span>min.</span>
 1203                            </div>
 1204                        </div>
 1205
 1206                        <div class="form-group d-flex align-items-center justify-content-end">
 1207                            <div class="flex-grow-1">
 1208                                <input asp-for="Orders[i].MaxOzonCommission"
 1209                                       class="form-control form-control-sm ozon-commission-field"
 1210                                       id="MaxOzonCommission_@Model.Orders[i].Id" style="text-align: right;"/>
 1211                                <span asp-validation-for="Orders[i].MaxOzonCommission" class="text-danger"
 1212                                      id="MaxOzonCommissionValidation_@Model.Orders[i].Id"></span>
 1213                            </div>
 1214                            <div style="margin-left: auto;">
 1215                                <span>max.</span>
 1216                            </div>
 1217                        </div>
 1218
 1219                    </td>
 1220                }
 1221                else
 1222                {
 1223                    <td class="tx-metric-col" data-column="commission" style="text-align: right;">
 1224                        <div id="MinOzonCommission_@Model.Orders[i].Id" title="@Model.Orders[i].MinCommissionInfo">
 01225                            @OrderCellFormat.Money(Model.Orders[i].MinOzonCommission)
 1226                        </div>
 1227                        <br/>
 1228                        <div id="MaxOzonCommission_@Model.Orders[i].Id" title="@Model.Orders[i].MaxCommissionInfo">
 01229                            @OrderCellFormat.Money(Model.Orders[i].MaxOzonCommission)
 1230                        </div>
 1231                    </td>
 1232                    <div class="form-group" style="display: none">
 1233                        <label asp-for="Orders[i].MinOzonCommission" class="control-label"></label><span
 1234                            style="margin-left: 10px; color: gray;">/ </span>
 1235                        <input asp-for="Orders[i].MinOzonCommission" class="form-control"/>
 1236                        <span asp-validation-for="Orders[i].MinOzonCommission" class="text-danger"></span>
 1237                    </div>
 1238                    <div class="form-group" style="display: none">
 1239                        <label asp-for="Orders[i].MaxOzonCommission" class="control-label"></label><span
 1240                            style="margin-left: 10px; color: gray;">/ </span>
 1241                        <input asp-for="Orders[i].MaxOzonCommission" class="form-control"/>
 1242                        <span asp-validation-for="Orders[i].MaxOzonCommission" class="text-danger"></span>
 1243                    </div>
 1244                }
 1245            }
 1246
 01247            @if (Col("Profit"))
 1248            {
 1249                <td class="tx-metric-col" data-column="profit" style="text-align: right;">
 1250                    <div>
 1251                        <span id="MaxProfit_@Model.Orders[i].Id">
 01252                            @if (Model.Orders[i].MaxProfit < 0)
 1253                            {
 01254                                <span style="color:red">@Html.DisplayFor(modelItem => Model.Orders[i].MaxProfit)</span>
 1255                            }
 1256                            else
 1257                            {
 01258                                @Html.DisplayFor(modelItem => Model.Orders[i].MaxProfit)
 1259                            }
 1260                        </span>
 1261                        <span id="TargetProfit_@Model.Orders[i].Id"
 1262                              class="text-muted"
 1263                              style="margin-left: 4px;"></span>
 1264                    </div>
 1265                    <br/>
 1266                    <div id="MinProfit_@Model.Orders[i].Id">
 01267                        @if (Model.Orders[i].MinProfit < 0)
 1268                        {
 01269                            <span style="color:red">@Html.DisplayFor(modelItem => Model.Orders[i].MinProfit)</span>
 1270                        }
 1271                        else
 1272                        {
 01273                            @Html.DisplayFor(modelItem => Model.Orders[i].MinProfit)
 1274                        }
 1275                    </div>
 1276                </td>
 1277            }
 1278
 01279            @if (Col("MarkupPercent"))
 1280            {
 1281                <td class="tx-metric-col" data-column="markup" style="text-align: right;">
 1282                    <div id="MaxDiscount_@Model.Orders[i].Id">
 01283                        @if (Model.Orders[i].MaxDiscount < 0)
 1284                        {
 01285                            <span style="color:red">@Html.DisplayFor(modelItem => Model.Orders[i].MaxDiscount)</span>
 1286                        }
 1287                        else
 1288                        {
 01289                            @Html.DisplayFor(modelItem => Model.Orders[i].MaxDiscount)
 1290                        }
 1291                    </div>
 1292                    <br/>
 1293                    <div id="MinDiscount_@Model.Orders[i].Id">
 01294                        @if (Model.Orders[i].MinDiscount < 0)
 1295                        {
 01296                            <span style="color:red">@Html.DisplayFor(modelItem => Model.Orders[i].MinDiscount)</span>
 1297                        }
 1298                        else
 1299                        {
 01300                            @Html.DisplayFor(modelItem => Model.Orders[i].MinDiscount)
 1301                        }
 1302                    </div>
 1303                </td>
 1304
 1305                <input asp-for="Orders[i].MinOzonCommission" type="hidden"/>
 1306                <input asp-for="Orders[i].MaxOzonCommission" type="hidden"/>
 1307            }
 1308        </tr>
 01309    }
 1310    </tbody>
 1311    <tfoot>
 1312    <tr>
 1313        <th></th>
 1314        <th colspan="10"></th>
 1315
 01316        @if (Col("ShipmentTotal"))
 1317        {
 1318            <th style="white-space: nowrap; text-align: right;">
 1319                <div id="totalShipmentAmount"></div>
 1320            </th>
 1321        }
 1322        else
 1323        {
 1324            <th></th>
 1325        }
 1326
 1327
 01328        @if (Col("PurchasePrice"))
 1329        {
 1330            <th colspan="3" style="white-space: nowrap; text-align: left;">
 1331                <div id="totalPurchasePriceRub"></div>
 1332            </th>
 1333        }
 1334        else
 1335        {
 1336            <th></th>
 1337        }
 1338    </tr>
 1339    </tfoot>
 1340    <input type="hidden" id="deletedOrders" name="deletedOrders"/>
 1341</table>
 1342</div>
 1343</div>
 1344
 1345<script>
 1346    document.addEventListener('DOMContentLoaded', () => {
 1347        const debounceMap = new Map();
 1348
 1349        document.querySelectorAll('.gtd-autocomplete').forEach((input) => {
 1350            const orderId = input.dataset.orderId;
 1351            if (!orderId) return;
 1352
 1353            let menu = document.getElementById(`gtdMenu_${orderId}`);
 1354            if (!menu) {
 1355                menu = document.createElement('ul');
 1356                menu.id = `gtdMenu_${orderId}`;
 1357                menu.className = 'list-group combobox-menu';
 1358                menu.style.cssText = 'position:fixed; z-index:2147483000; min-width:100%; width:max-content; max-width:9
 1359                const wrapper = input.closest('.form-group');
 1360                if (!wrapper) return;
 1361                wrapper.classList.add('position-relative');
 1362                wrapper.appendChild(menu);
 1363            }
 1364
 1365            const placeMenu = () => {
 1366                const rect = input.getBoundingClientRect();
 1367                menu.style.left = `${rect.left}px`;
 1368                menu.style.top = `${rect.bottom + 2}px`;
 1369                menu.style.minWidth = `${rect.width}px`;
 1370            };
 1371
 1372            const hideMenu = () => {
 1373                menu.style.display = 'none';
 1374                menu.innerHTML = '';
 1375            };
 1376
 1377            input.addEventListener('blur', () => {
 1378                setTimeout(hideMenu, 150);
 1379            });
 1380
 1381            const loadSuggestions = async (query, limit) => {
 1382                try {
 1383                    const url = `/Studio2/ShippedBySupplierTransaction/SearchGtd?query=${encodeURIComponent(query)}&limi
 1384                    const response = await fetch(url, { credentials: 'same-origin' });
 1385                    if (!response.ok) {
 1386                        hideMenu();
 1387                        return;
 1388                    }
 1389
 1390                    const items = await response.json();
 1391                    menu.innerHTML = '';
 1392
 1393                    if (!Array.isArray(items) || items.length === 0) {
 1394                        hideMenu();
 1395                        return;
 1396                    }
 1397
 1398                    items.forEach((code) => {
 1399                        const li = document.createElement('li');
 1400                        li.className = 'list-group-item list-group-item-action combobox-item';
 1401                        li.setAttribute('role', 'option');
 1402                        li.textContent = code;
 1403                        li.addEventListener('mousedown', () => {
 1404                            input.value = code;
 1405                            hideMenu();
 1406                        });
 1407                        menu.appendChild(li);
 1408                    });
 1409
 1410                    placeMenu();
 1411                    menu.style.display = 'block';
 1412                } catch (e) {
 1413                    hideMenu();
 1414                }
 1415            };
 1416
 1417            input.addEventListener('focus', () => {
 1418                const query = input.value.trim();
 1419                if (query.length === 0) {
 1420                    loadSuggestions('', 10);
 1421                }
 1422            });
 1423
 1424            input.addEventListener('input', () => {
 1425                const query = input.value.trim();
 1426                if (debounceMap.has(input)) clearTimeout(debounceMap.get(input));
 1427
 1428                const timeoutId = setTimeout(async () => {
 1429                    if (query.length === 0) {
 1430                        await loadSuggestions('', 10);
 1431                        return;
 1432                    }
 1433
 1434                    await loadSuggestions(query, 20);
 1435                }, 250);
 1436
 1437                debounceMap.set(input, timeoutId);
 1438            });
 1439
 1440            input.addEventListener('click', () => {
 1441                if (input.value.trim().length === 0) {
 1442                    loadSuggestions('', 10);
 1443                }
 1444            });
 1445        });
 1446
 1447        const countryInputs = document.querySelectorAll('input[id^="orderCountryMap_"]');
 1448        countryInputs.forEach((input) => {
 1449            const orderId = input.id.replace('orderCountryMap_', '');
 1450            const menu = document.getElementById(`countryMenu_${orderId}`);
 1451            if (!menu) return;
 1452
 1453            const allItems = Array.from(menu.querySelectorAll('.combobox-item'))
 1454                .map((li) => li.getAttribute('data-value') || '')
 1455                .filter((v) => v.trim().length > 0)
 1456                .sort((a, b) => a.localeCompare(b, 'ru', { sensitivity: 'base' }));
 1457
 1458            const placeMenu = () => {
 1459                const rect = input.getBoundingClientRect();
 1460                menu.style.left = `${rect.left}px`;
 1461                menu.style.top = `${rect.bottom + 2}px`;
 1462                menu.style.minWidth = `${rect.width}px`;
 1463            };
 1464
 1465            const hideMenu = () => {
 1466                menu.style.display = 'none';
 1467                menu.innerHTML = '';
 1468            };
 1469
 1470            const renderMenu = (items) => {
 1471                menu.innerHTML = '';
 1472                if (!items.length) {
 1473                    hideMenu();
 1474                    return;
 1475                }
 1476
 1477                items.forEach((country) => {
 1478                    const li = document.createElement('li');
 1479                    li.className = 'list-group-item list-group-item-action combobox-item';
 1480                    li.setAttribute('role', 'option');
 1481                    li.setAttribute('data-value', country);
 1482                    li.textContent = country;
 1483                    li.addEventListener('mousedown', () => {
 1484                        input.value = country;
 1485                        hideMenu();
 1486                    });
 1487                    menu.appendChild(li);
 1488                });
 1489
 1490                placeMenu();
 1491                menu.style.display = 'block';
 1492            };
 1493
 1494            const showDefault = () => renderMenu(allItems.slice(0, 10));
 1495
 1496            input.addEventListener('focus', () => {
 1497                if (input.value.trim().length === 0) showDefault();
 1498            });
 1499
 1500            input.addEventListener('click', () => {
 1501                if (input.value.trim().length === 0) showDefault();
 1502            });
 1503
 1504            input.addEventListener('input', () => {
 1505                const q = input.value.trim().toLocaleLowerCase();
 1506                if (!q) {
 1507                    showDefault();
 1508                    return;
 1509                }
 1510
 1511                const matched = allItems.filter((x) => x.toLocaleLowerCase().includes(q)).slice(0, 20);
 1512                renderMenu(matched);
 1513            });
 1514
 1515            input.addEventListener('blur', () => setTimeout(hideMenu, 150));
 1516        });
 1517    });
 1518</script>
 1519
 1520<div id="selectedSuppliersList"></div>
 1521
 1522@* Форма загрузки файлов вынесена за пределы основной формы транзакции *@
 01523@if (Model.Orders != null && Model.Orders.Any())
 1524{
 1525    <div class="mt-3 mb-3" id="fileUploadContainer" style="position: relative; z-index: 1;">
 1526        <div class="card rounded-0 border-start-0 border-end-0">
 1527            <div class="card-header bg-light p-2">
 1528                <h6 class="mb-0" style="font-size: 0.9rem;">Загрузка файлов</h6>
 1529            </div>
 1530            <div class="card-body p-2">
 1531                <div id="fileUploadFormWrapper">
 1532                    <input type="file" class="form-control form-control-sm" id="fileInput" name="file"/>
 01533                    @foreach (var order in Model.Orders)
 1534                    {
 1535                        <input type="hidden" name="orderIds" value="@order.Id"/>
 1536                    }
 1537                </div>
 1538                <div id="uploadStatus" class="mb-2 mt-2" style="display: none;"></div>
 1539                @{
 01540                    var ordersWithDocuments = Model.Orders
 01541                        .Where(o => o.OrderExtensions != null &&
 01542                                   o.OrderExtensions.Any(e => e.Key == "Документ транзакции" && !string.IsNullOrEmpty(e.
 01543                        .Select(o => new
 01544                        {
 01545                            Order = o,
 01546                            DocumentPath = o.OrderExtensions?.FirstOrDefault(e => e.Key == "Документ транзакции")?.Value
 01547                        })
 01548                        .Where(x => !string.IsNullOrEmpty(x.DocumentPath))
 01549                        .ToList();
 1550                }
 01551                @if (ordersWithDocuments.Any())
 1552                {
 1553                    <div class="alert alert-warning mb-0 p-2 mt-2" style="font-size: 0.85rem;">
 1554                        <i class="fas fa-info-circle me-1"></i>Файл уже загружен для заказов в этой транзакции:
 01555                        @foreach (var item in ordersWithDocuments)
 1556                        {
 01557                            <br><small class="text-muted">Заказ <strong>@item.Order.ShipmentNumber</strong>: @item.Docum
 1558                        }
 1559                    </div>
 1560                }
 01561                <small class="text-muted" style="font-size: 0.75rem;">Файл будет загружен автоматически после выбора (не
 1562            </div>
 1563        </div>
 1564    </div>
 1565}
 1566
 1567<div class="mt-3 mb-3">
 1568    <div class="card rounded-0 border-start-0 border-end-0">
 1569        <div class="card-header bg-light">
 1570            <h6 class="mb-0">Курсы валют</h6>
 1571        </div>
 1572        <div class="card-body p-2">
 1573            <div class="d-flex flex-wrap align-items-center gap-3 ps-2">
 1574                <div>
 01575                    <strong>USD:</strong> <span class="ms-1">@Model.RateUSD.ToString().Replace(',', '.')</span>
 1576                </div>
 1577                <div>
 01578                    <strong>EUR:</strong> <span class="ms-1">@Model.RateEUR.ToString().Replace(',', '.')</span>
 1579                </div>
 1580                <div>
 01581                    <strong>BYN:</strong> <span class="ms-1">@Model.RateBYN.ToString().Replace(',', '.')</span>
 1582                </div>
 1583            </div>
 1584        </div>
 1585    </div>
 1586</div>
 1587
 01588@await Html.PartialAsync("~/Areas/Studio2/Views/Partials/Transaction/_TransactionCommentField.cshtml")
 1589
 1590<input type="hidden" name="stockItemsJson" id="stockItemsJson"/>
 1591
 1592<script>
 1593    // Функция для показа уведомлений
 1594    function showNotification(message, type = 'info') {
 1595        // Создаем контейнер для уведомлений если его нет
 1596        let notificationContainer = document.getElementById('notification-container');
 1597        if (!notificationContainer) {
 1598            notificationContainer = document.createElement('div');
 1599            notificationContainer.id = 'notification-container';
 1600            notificationContainer.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 99999; display: fle
 1601            document.body.appendChild(notificationContainer);
 1602        }
 1603
 1604        // Создаем уведомление
 1605        const toast = document.createElement('div');
 1606        toast.className = `alert alert-${type} alert-dismissible fade show`;
 1607        toast.style.cssText = 'min-width: 300px; max-width: 500px; box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);';
 1608        toast.innerHTML = `
 1609            <div style="font-size: 0.9rem;">${message}</div>
 1610            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
 1611        `;
 1612
 1613        // Добавляем уведомление в контейнер
 1614        notificationContainer.appendChild(toast);
 1615
 1616        // Инициализируем Bootstrap alert
 1617        const bsAlert = new bootstrap.Alert(toast);
 1618
 1619        // Автоматическое скрытие через 8 секунд
 1620        setTimeout(() => {
 1621            if (toast.parentNode) {
 1622                bsAlert.close();
 1623            }
 1624        }, 8000);
 1625
 1626        // Удаляем элемент из DOM после скрытия
 1627        toast.addEventListener('closed.bs.alert', function () {
 1628            if (toast.parentNode) {
 1629                toast.parentNode.removeChild(toast);
 1630            }
 1631        });
 1632    }
 1633
 1634    // Обработка загрузки файлов - автоматическая загрузка при выборе файла
 1635    (function() {
 1636        function initFileUpload() {
 1637            const fileUploadContainer = document.getElementById('fileUploadContainer');
 1638            if (!fileUploadContainer) return;
 1639
 1640            const fileInput = fileUploadContainer.querySelector('#fileInput');
 1641            const uploadStatus = fileUploadContainer.querySelector('#uploadStatus');
 1642
 1643            if (!fileInput) return;
 1644
 1645            // Обрабатываем изменение файла - автоматическая загрузка
 1646            fileInput.addEventListener('change', async function (e) {
 1647                // Проверяем, что событие именно от нашего поля
 1648                if (e.target !== fileInput) return;
 1649
 1650                // Останавливаем всплытие, но НЕ блокируем другие обработчики
 1651                e.stopPropagation();
 1652
 1653                const file = fileInput.files[0];
 1654                if (!file) {
 1655                    return;
 1656                }
 1657
 1658                // Собираем все orderIds из скрытых полей внутри контейнера
 1659                const orderIds = Array.from(fileUploadContainer.querySelectorAll('input[name="orderIds"]'))
 1660                    .map(input => parseInt(input.value))
 1661                    .filter(id => !isNaN(id));
 1662
 1663                if (orderIds.length === 0) {
 1664                    showNotification('Не найдено ни одного заказа для загрузки файла', 'warning');
 1665                    fileInput.value = '';
 1666                    return;
 1667                }
 1668
 1669                // Создаем FormData
 1670                const formData = new FormData();
 1671                formData.append('file', file);
 1672                orderIds.forEach(id => {
 1673                    formData.append('orderIds', id);
 1674                });
 1675
 1676                // Добавляем токен антифоржеризации, если он есть
 1677                const token = document.querySelector('input[name="__RequestVerificationToken"]')?.value;
 1678                if (token) {
 1679                    formData.append('__RequestVerificationToken', token);
 1680                }
 1681
 1682                // Блокируем поле и показываем статус
 1683                fileInput.disabled = true;
 1684                uploadStatus.style.display = 'block';
 1685                uploadStatus.innerHTML = '<div class="alert alert-info mb-0 p-2" style="font-size: 0.85rem;"><span class
 1686
 1687                try {
 01688                    const response = await fetch('@Url.Action("UploadFile", "TransactionFiles", new { area = "Studio2" }
 1689                        method: 'POST',
 1690                        body: formData
 1691                    });
 1692
 1693                    const result = await response.json();
 1694
 1695                    if (response.ok) {
 1696                        const folderPath = result.dropboxFolderPath || '';
 1697                        uploadStatus.innerHTML = `<div class="alert alert-success mb-0 p-2" style="font-size: 0.85rem;">
 1698                            <i class="fas fa-check-circle me-1"></i>${result.message || 'Файл успешно загружен'}
 1699                            ${folderPath ? `<br><small class="text-muted">Путь: ${folderPath}</small>` : ''}
 1700                            ${result.path ? `<br><a href="${result.path}" target="_blank" class="alert-link" style="font
 1701                        </div>`;
 1702                        const notificationMessage = folderPath
 1703                            ? `Файл успешно загружен в: ${folderPath}`
 1704                            : 'Файл успешно загружен';
 1705                        showNotification(notificationMessage, 'success');
 1706                        // Очищаем поле после успешной загрузки
 1707                        setTimeout(() => {
 1708                            fileInput.value = '';
 1709                            fileInput.disabled = false;
 1710                        }, 2000);
 1711                    } else {
 1712                        uploadStatus.innerHTML = `<div class="alert alert-danger mb-0 p-2" style="font-size: 0.85rem;">
 1713                            <i class="fas fa-exclamation-circle me-1"></i>${result.error || 'Ошибка при загрузке файла'}
 1714                        </div>`;
 1715                        showNotification(result.error || 'Ошибка при загрузке файла', 'danger');
 1716                        fileInput.value = '';
 1717                        fileInput.disabled = false;
 1718                    }
 1719                } catch (error) {
 1720                    uploadStatus.innerHTML = `<div class="alert alert-danger mb-0 p-2" style="font-size: 0.85rem;">
 1721                        <i class="fas fa-exclamation-circle me-1"></i>Ошибка: ${error.message}
 1722                    </div>`;
 1723                    showNotification('Ошибка при загрузке файла: ' + error.message, 'danger');
 1724                    fileInput.value = '';
 1725                    fileInput.disabled = false;
 1726                }
 1727            });
 1728        }
 1729
 1730        // Инициализация при загрузке DOM
 1731        if (document.readyState === 'loading') {
 1732            document.addEventListener('DOMContentLoaded', initFileUpload);
 1733        } else {
 1734            initFileUpload();
 1735        }
 1736    })();
 1737
 1738    // Обработчик клика на стрелки количества
 1739    document.addEventListener('DOMContentLoaded', function () {
 1740        // Инициализация скрытых полей значениями из отображаемых span
 1741        document.querySelectorAll('.quantity-display').forEach(function (span) {
 1742            const orderId = span.getAttribute('data-order-id');
 1743            const hiddenInput = document.querySelector(`input.quantity-hidden-input[data-order-id="${orderId}"]`);
 1744            if (hiddenInput && !hiddenInput.value) {
 1745                hiddenInput.value = span.textContent.trim();
 1746            }
 1747        });
 1748
 1749        // Обработчики для кнопок-стрелок
 1750        document.querySelectorAll('.quantity-arrow-btn').forEach(function (btn) {
 1751            btn.addEventListener('click', function () {
 1752                const orderId = this.getAttribute('data-order-id');
 1753                const action = this.getAttribute('data-action');
 1754                const originalQuantity = parseFloat(this.getAttribute('data-original-quantity')) || 0;
 1755
 1756                // Находим скрытое поле и отображаемое значение
 1757                const hiddenInput = document.querySelector(`input.quantity-hidden-input[data-order-id="${orderId}"]`);
 1758                const displaySpan = document.querySelector(`span.quantity-display[data-order-id="${orderId}"]`);
 1759
 1760                if (!hiddenInput || !displaySpan) return;
 1761
 1762                let currentValue = parseFloat(hiddenInput.value) || originalQuantity;
 1763
 1764                // Изменяем значение
 1765                if (action === 'increment') {
 1766                    currentValue = Math.min(currentValue + 1, originalQuantity);
 1767                } else if (action === 'decrement') {
 1768                    currentValue = Math.max(currentValue - 1, 0);
 1769                }
 1770
 1771                // Обновляем значения
 1772                hiddenInput.value = currentValue;
 1773                displaySpan.textContent = currentValue;
 1774
 1775                // Визуальная индикация изменения
 1776                const originalQty = parseFloat(this.getAttribute('data-original-quantity')) || 0;
 1777                if (currentValue !== originalQuantity) {
 1778                    displaySpan.classList.add('quantity-changed');
 1779                    displaySpan.classList.remove('qty-value--multi', 'qty-value--zero');
 1780                    displaySpan.style.color = '';
 1781                    displaySpan.style.fontWeight = '';
 1782                } else {
 1783                    displaySpan.classList.remove('quantity-changed');
 1784                    displaySpan.classList.remove('qty-value--multi', 'qty-value--zero');
 1785                    displaySpan.style.color = '';
 1786                    displaySpan.style.fontWeight = '';
 1787                    if (currentValue === 0 && originalQty > 0) {
 1788                        displaySpan.classList.add('qty-value--zero');
 1789                    } else if (currentValue > 1) {
 1790                        displaySpan.classList.add('qty-value--multi');
 1791                    }
 1792                }
 1793
 1794                // Показываем сообщение об изменении
 1795                if (currentValue !== originalQuantity) {
 1796                    showQuantityChangeMessage(hiddenInput, currentValue, originalQuantity);
 1797                }
 1798            });
 1799        });
 1800
 1801        // Подсказки кнопок-стрелок обслуживает единый движок js/tooltip.js.
 1802    });
 1803</script>
 1804
 1805<script>
 1806    // Обработчик для сканера штрих-кодов с поиском в таблице
 1807    document.addEventListener('DOMContentLoaded', function() {
 1808        // Создаем скрытое поле для сканера, если его еще нет
 1809        let barcodeInput = document.getElementById('barcode');
 1810        if (!barcodeInput) {
 1811            barcodeInput = document.createElement('input');
 1812            barcodeInput.type = 'text';
 1813            barcodeInput.id = 'barcode';
 1814            barcodeInput.name = 'barcode';
 1815            barcodeInput.style.cssText = 'position: fixed; left: -9999px; top: 0; width: 1px; height: 1px; opacity: 0;';
 1816            barcodeInput.setAttribute('autocomplete', 'off');
 1817            barcodeInput.setAttribute('tabindex', '-1');
 1818            document.body.appendChild(barcodeInput);
 1819        }
 1820
 1821        // Переменные для хранения предыдущих выделений
 1822        let previousHighlightedRows = [];
 1823        let highlightTimeout = null;
 1824
 1825        // Функция для добавления иконки сканирования рядом с кодом
 1826        function addScanIcon(row, scanCode) {
 1827            // Удаляем предыдущую иконку, если она есть
 1828            const existingIcon = row.querySelector('.scan-success-icon');
 1829            if (existingIcon) {
 1830                existingIcon.remove();
 1831            }
 1832
 1833            // Ищем ячейку с номером отправления или артикулом
 1834            let shipmentNumberCell = null;
 1835            const allCells = row.querySelectorAll('td');
 1836
 1837            for (let cell of allCells) {
 1838                // Проверяем наличие скрытого поля с ShipmentNumber
 1839                const shipmentInput = cell.querySelector('input[name*="ShipmentNumber"]');
 1840                if (shipmentInput) {
 1841                    shipmentNumberCell = cell;
 1842                    break;
 1843                }
 1844                // Или проверяем текстовое содержимое
 1845                const cellText = cell.textContent || cell.innerText;
 1846                if (cellText.includes(scanCode)) {
 1847                    shipmentNumberCell = cell;
 1848                    break;
 1849                }
 1850            }
 1851
 1852            if (!shipmentNumberCell) {
 1853                return;
 1854            }
 1855
 1856            // Создаем контейнер для иконки
 1857            const iconContainer = document.createElement('span');
 1858            iconContainer.className = 'scan-success-icon';
 1859            iconContainer.style.cssText = 'display: inline-flex; align-items: center; margin-left: 8px; vertical-align: 
 1860            iconContainer.title = 'Отсканировано: ' + scanCode;
 1861
 1862            // Создаем SVG иконку штрих-кода
 1863            const iconSvg = `
 1864                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
 1865                     viewBox="0 0 16 16" style="color: #28a745;">
 1866                    <path d="M2 2h2v12H2V2zm3 0h1v12H5V2zm2 0h2v12H7V2zm3 0h1v12h-1V2zm2 0h1v12h-1V2zm2 0h1v12h-1V2z"/>
 1867                    <path d="M0 2a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm1 0v12a1 1 0 0 0 1 
 1868                </svg>
 1869            `;
 1870
 1871            iconContainer.innerHTML = iconSvg;
 1872
 1873            // Ищем место для вставки иконки (рядом с номером отправления)
 1874            // Сначала ищем span с row-number
 1875            let targetElement = null;
 1876            const spansWithRowNumber = shipmentNumberCell.querySelectorAll('span');
 1877            for (let span of spansWithRowNumber) {
 1878                if (span.querySelector('b.row-number')) {
 1879                    targetElement = span;
 1880                    break;
 1881                }
 1882            }
 1883
 1884            // Если не нашли, ищем любой span или div
 1885            if (!targetElement) {
 1886                targetElement = shipmentNumberCell.querySelector('span') ||
 1887                              shipmentNumberCell.querySelector('div');
 1888            }
 1889
 1890            if (targetElement) {
 1891                // Добавляем иконку в контейнер с номером отправления
 1892                targetElement.appendChild(iconContainer);
 1893            } else {
 1894                // Если не нашли подходящий контейнер, добавляем в начало ячейки
 1895                shipmentNumberCell.insertBefore(iconContainer, shipmentNumberCell.firstChild);
 1896            }
 1897
 1898            // Добавляем анимацию появления
 1899            iconContainer.style.opacity = '0';
 1900            iconContainer.style.transform = 'scale(0.8)';
 1901            iconContainer.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
 1902
 1903            setTimeout(() => {
 1904                iconContainer.style.opacity = '1';
 1905                iconContainer.style.transform = 'scale(1)';
 1906            }, 10);
 1907        }
 1908
 1909        // Функция для снятия выделения со всех строк
 1910        function removeAllHighlights() {
 1911            previousHighlightedRows.forEach(row => {
 1912                if (row) {
 1913                    row.style.border = '';
 1914                    row.style.boxShadow = '';
 1915                    row.style.transition = '';
 1916            }
 1917            });
 1918            previousHighlightedRows = [];
 1919
 1920            // Убираем выделение со всех строк
 1921            const table = document.getElementById('shipmentTable');
 1922            if (table) {
 1923                table.querySelectorAll('tbody tr').forEach(row => {
 1924                    row.style.border = '';
 1925                    row.style.boxShadow = '';
 1926                    row.style.transition = '';
 1927                });
 1928            }
 1929            // Очищаем таймер, если он был установлен
 1930            if (highlightTimeout) {
 1931                clearTimeout(highlightTimeout);
 1932                highlightTimeout = null;
 1933            }
 1934        }
 1935
 1936        // Функция для поиска и выделения строки
 1937        function findAndHighlightRow(searchCode) {
 1938            if (!searchCode || searchCode.trim() === '') {
 1939                return false;
 1940            }
 1941
 1942            const table = document.getElementById('shipmentTable');
 1943            if (!table) {
 1944                console.warn('Таблица shipmentTable не найдена');
 1945                if (typeof showNotification === 'function') {
 1946                    showNotification('Таблица не найдена', 'danger');
 1947                }
 1948                return false;
 1949            }
 1950
 1951            const rows = table.querySelectorAll('tbody tr[id^="orderRow_"]');
 1952            let foundRows = [];
 1953
 1954            // Определяем формат кода
 1955            const isOrderNumber = searchCode.includes('-');
 1956            const isEAN = /^\d{8}$|^\d{12}$|^\d{13}$/.test(searchCode);
 1957
 1958            // Ищем все строки по номеру отправления или штрихкоду
 1959            for (let row of rows) {
 1960                let found = false;
 1961
 1962                if (isOrderNumber) {
 1963                    // Поиск по номеру заказа
 1964                    const shipmentNumberInput = row.querySelector('input[name*="ShipmentNumber"]');
 1965                    const shipmentNumber = shipmentNumberInput ? shipmentNumberInput.value : '';
 1966                const rowText = row.textContent || row.innerText;
 1967
 1968                    if ((shipmentNumber && shipmentNumber.includes(searchCode)) ||
 1969                        rowText.includes(searchCode)) {
 1970                        found = true;
 1971                    }
 1972                } else if (isEAN) {
 1973                    // Поиск по штрихкоду (EAN)
 1974                    const barcode = row.getAttribute('data-barcode');
 1975                    if (barcode && barcode.trim() === searchCode.trim()) {
 1976                        found = true;
 1977                    }
 1978                } else {
 1979                    // Поиск по номеру заказа (по умолчанию для обратной совместимости)
 1980                const shipmentNumberInput = row.querySelector('input[name*="ShipmentNumber"]');
 1981                const shipmentNumber = shipmentNumberInput ? shipmentNumberInput.value : '';
 1982                    const rowText = row.textContent || row.innerText;
 1983
 1984                // Ищем артикул в тексте строки (может быть в разных местах)
 1985                const articleCells = row.querySelectorAll('[id*="Article"], [id*="thArticle"]');
 1986                let articleFound = false;
 1987                articleCells.forEach(cell => {
 1988                    const cellText = cell.textContent || cell.innerText;
 1989                    if (cellText.includes(searchCode)) {
 1990                        articleFound = true;
 1991                    }
 1992                });
 1993
 1994                if ((shipmentNumber && shipmentNumber.includes(searchCode)) ||
 1995                    (rowText.includes(searchCode) && (articleFound || rowText.indexOf(searchCode) !== -1))) {
 1996                        found = true;
 1997                    }
 1998                }
 1999
 2000                if (found) {
 2001                    foundRows.push(row);
 2002                }
 2003            }
 2004
 2005            if (foundRows.length > 0) {
 2006                // Снимаем предыдущее выделение
 2007                removeAllHighlights();
 2008
 2009                // Выделяем все найденные строки обводкой
 2010                foundRows.forEach((row, index) => {
 2011                    row.style.border = '3px solid #0d6efd';
 2012                    row.style.boxShadow = '0 0 10px rgba(13, 110, 253, 0.5)';
 2013                    row.style.transition = 'border 0.3s ease, box-shadow 0.3s ease';
 2014                    previousHighlightedRows.push(row);
 2015
 2016                // Добавляем иконку сканирования рядом с кодом
 2017                    addScanIcon(row, searchCode);
 2018
 2019                    // Прокручиваем к первой найденной строке
 2020                    if (index === 0) {
 2021                        row.scrollIntoView({
 2022                    behavior: 'smooth',
 2023                    block: 'center'
 2024                        });
 2025                    }
 2026                });
 2027
 2028                // Показываем уведомление об успешном поиске
 2029                const searchType = isEAN ? 'по EAN' : 'по номеру заказа';
 2030                const countText = foundRows.length > 1 ? ` (найдено: ${foundRows.length})` : '';
 2031                if (typeof showNotification === 'function') {
 2032                    showNotification(`Заказ${foundRows.length > 1 ? 'ы' : ''} найден${foundRows.length > 1 ? 'ы' : ''} $
 2033                }
 2034
 2035                // Автоматически снимаем выделение через 5 секунд
 2036                highlightTimeout = setTimeout(() => {
 2037                    foundRows.forEach(row => {
 2038                        if (row) {
 2039                            row.style.border = '';
 2040                            row.style.boxShadow = '';
 2041                            row.style.transition = '';
 2042                        }
 2043                    });
 2044                    previousHighlightedRows = [];
 2045                }, 5000);
 2046
 2047                return true;
 2048            } else {
 2049                // Если не найдено, показываем уведомление
 2050                const searchType = isEAN ? 'по EAN' : 'по номеру заказа';
 2051                console.warn(`Строка с кодом "${searchCode}" не найдена`);
 2052                if (typeof showNotification === 'function') {
 2053                    showNotification(`Заказ ${searchType} "${searchCode}" не найден`, 'warning');
 2054                }
 2055                return false;
 2056            }
 2057        }
 2058
 2059        // Обработчик события keydown для сканера
 2060        barcodeInput.addEventListener('keydown', function(e) {
 2061            if (e.key === 'Enter') {
 2062                e.preventDefault();
 2063                const code = barcodeInput.value.trim();
 2064
 2065                if (code) {
 2066                    // Ищем и выделяем строку
 2067                    findAndHighlightRow(code);
 2068
 2069                    // Очищаем поле сканера
 2070                    barcodeInput.value = '';
 2071                }
 2072            }
 2073        });
 2074
 2075        // Автоматически устанавливаем фокус на поле сканера при загрузке страницы
 2076        // Используем setTimeout чтобы избежать прокрутки страницы
 2077        setTimeout(function() {
 2078            if (document.activeElement !== barcodeInput) {
 2079                barcodeInput.focus();
 2080            }
 2081        }, 100);
 2082
 2083        // Устанавливаем фокус на поле сканера при клике в любом месте страницы
 2084        // (если клик не по интерактивному элементу)
 2085        // Переменная для отслеживания выделения текста
 2086        let isSelectingText = false;
 2087        let mouseDownTime = 0;
 2088
 2089        document.addEventListener('mousedown', function(e) {
 2090            mouseDownTime = Date.now();
 2091            isSelectingText = false;
 2092        });
 2093
 2094        document.addEventListener('mousemove', function(e) {
 2095            if (mouseDownTime > 0 && Date.now() - mouseDownTime > 10) {
 2096                isSelectingText = true;
 2097            }
 2098        });
 2099
 2100        document.addEventListener('mouseup', function(e) {
 2101            setTimeout(function() {
 2102                isSelectingText = false;
 2103                mouseDownTime = 0;
 2104            }, 100);
 2105        });
 2106
 2107        document.addEventListener('click', function(e) {
 2108            // Проверяем, есть ли выделенный текст
 2109            const selection = window.getSelection();
 2110            const hasSelection = selection && selection.toString().trim().length > 0;
 2111
 2112            // Если есть выделенный текст или происходит выделение, не устанавливаем фокус
 2113            if (hasSelection || isSelectingText) {
 2114                return;
 2115            }
 2116
 2117            // Если клик не по интерактивному элементу
 2118            if (e.target.tagName !== 'INPUT' &&
 2119                e.target.tagName !== 'TEXTAREA' &&
 2120                e.target.tagName !== 'SELECT' &&
 2121                e.target.tagName !== 'BUTTON' &&
 2122                e.target.tagName !== 'A' &&
 2123                e.target.tagName !== 'TD' &&
 2124                e.target.tagName !== 'TH' &&
 2125                e.target.tagName !== 'SPAN' &&
 2126                !e.target.closest('.dropdown-menu') &&
 2127                !e.target.closest('.modal') &&
 2128                !e.target.closest('.btn') &&
 2129                !e.target.closest('.form-control') &&
 2130                !e.target.closest('table')) {
 2131                // Устанавливаем фокус на поле сканера с небольшой задержкой
 2132                setTimeout(function() {
 2133                    // Повторно проверяем выделение перед установкой фокуса
 2134                    const currentSelection = window.getSelection();
 2135                    if (!currentSelection || !currentSelection.toString().trim()) {
 2136                    barcodeInput.focus();
 2137                    }
 2138                }, 100);
 2139            }
 2140        });
 2141
 2142        // Обработка клавиши Escape для снятия выделения
 2143        document.addEventListener('keydown', function(e) {
 2144            if (e.key === 'Escape') {
 2145                removeAllHighlights();
 2146            }
 2147        });
 2148    });
 2149</script>