< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_OneCStock_Index
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OneCStock/Index.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 7
Coverable lines: 7
Total lines: 330
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 100
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%210140%
<ExecuteAsync()0%7482860%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OneCStock/Index.cshtml

#LineLine coverage
 1@using OzonOrdersWeb.Areas.Studio2.ViewModels.OneCStock
 2@model OneCStockIndexViewModel
 3@{
 04    ViewData["Title"] = "Остатки 1С по складам";
 05    var pageModel = Model!;
 6}
 7<link rel="stylesheet" href="~/css/Studio2/shared/section-hero.css" asp-append-version="true" />
 8<link rel="stylesheet" href="~/css/Studio2/shared/quick-links-chip.css" asp-append-version="true" />
 9<link rel="stylesheet" href="~/css/Studio2/OneCStock/onec-stock.css" asp-append-version="true" />
 10
 11<div class="container-fluid px-3 py-3 ocs-page">
 12    <!-- Hero блок со статистикой и ссылками -->
 13    <div class="ocs-hero app-section-hero app-section-hero--import d-flex flex-wrap justify-content-between align-items-
 14        <div>
 15            <h1><i class="fas fa-pallet me-2 text-primary"></i>Остатки 1С по складам</h1>
 16            <div class="subtitle">Номенклатура на выбранном складе 1С с фильтром по сроку поступления</div>
 17            <div class="subtitle-help">
 18                Данные читаются из 1С онлайн без промежуточных таблиц. Первая загрузка склада занимает
 19                несколько секунд, далее выборка кэшируется. Кнопка «Обновить из 1С» принудительно перечитывает остатки.
 20            </div>
 21            <div class="ocs-quick-links app-section-hero__quick-links">
 22                <a asp-area="Studio2" asp-controller="WarehouseStock" asp-action="Index">
 23                    <i class="fas fa-warehouse"></i>Остатки склада
 24                </a>
 25                <a href="/Studio2/BitrixStock?tab=sync">
 26                    <i class="fas fa-boxes-stacked"></i>Остатки 1С → Ozon
 27                </a>
 28                <a asp-area="Studio2" asp-controller="JobLogs" asp-action="Index">
 29                    <i class="fas fa-list-alt"></i>Логи задач
 30                </a>
 31            </div>
 32        </div>
 33        <div class="ocs-stats d-flex flex-wrap gap-2 align-items-center">
 34            <div class="ocs-stat">
 35                <div class="label">Позиций (фильтр)</div>
 36                <div class="value" id="ocs-total">—</div>
 37            </div>
 38            <div class="ocs-stat">
 39                <div class="label">Всего на складе</div>
 40                <div class="value" id="ocs-total-positions">—</div>
 41            </div>
 42            <div class="ocs-stat">
 43                <div class="label">Суммарно шт.</div>
 44                <div class="value" id="ocs-total-quantity">—</div>
 45            </div>
 46            <div class="ocs-stat d-none d-md-block">
 47                <div class="label">Снимок 1С</div>
 48                <div class="value small" id="ocs-snapshot-time">—</div>
 49            </div>
 50        </div>
 51    </div>
 52
 53    <!-- Инфоблок с правилами расчёта -->
 54    <div class="ocs-intro">
 55        <i class="fas fa-circle-info"></i>
 56        <div class="ocs-intro-text">
 57            <strong>Как работает расчёт:</strong> срок считается по проведённым приходам позиции на склад (приходные нак
 58            Если по номенклатуре был хотя бы один свежий приход, вся позиция считается свежей (партии в OData регистре н
 59            Фильтры «Тип документа» и «Поставщик» смотрят на <em>последний</em> приход позиции на склад: остаётся то, чт
 60            Поиск идёт по артикулу и производителю; наименования подгружаются онлайн только для показанных строк.
 61        </div>
 62    </div>
 63
 064    @if (pageModel.OneCUnavailable)
 65    {
 66        <div class="alert alert-danger shadow-sm">
 67            <i class="fas fa-triangle-exclamation me-2"></i>
 68            Список складов не загружен — 1С временно недоступна. Обновите страницу позже.
 69        </div>
 70    }
 71    else
 72    {
 73        <!-- Карточка фильтров: data-no-loading="true" предотвращает бесконечную глобальную полосу загрузки -->
 74        <form id="ocs-filter" class="ocs-filter card shadow-sm mb-3" data-no-loading="true">
 75            <div class="card-body">
 76                <!-- Основная строка фильтров: Склад, Срок поступления, Параметры срока -->
 77                <div class="ocs-filter-top">
 78                    <div class="ocs-filter-field">
 79                        <label class="form-label" for="ocs-warehouse">
 80                            <i class="fas fa-warehouse text-primary me-1"></i>Склад 1С <span class="text-danger">*</span
 81                        </label>
 82                        <select id="ocs-warehouse" class="form-select form-select-sm custom-select-init">
 83                            <option value="">— выберите склад —</option>
 084                            @foreach (var warehouse in pageModel.Warehouses)
 85                            {
 086                                <option value="@warehouse.RefKey" selected="@(warehouse.RefKey == pageModel.SelectedWare
 87                            }
 88                        </select>
 89                    </div>
 90
 91                    <div class="ocs-filter-field">
 92                        <label class="form-label" for="ocs-mode">
 93                            <i class="fas fa-calendar-alt text-secondary me-1"></i>Срок поступления
 94                        </label>
 95                        <select id="ocs-mode" class="form-select form-select-sm custom-select-init">
 96                            <option value="none">Без ограничения</option>
 97                            <option value="older">Лежит дольше N дней</option>
 98                            <option value="range">Приход в диапазоне дат</option>
 99                        </select>
 100                    </div>
 101
 102                    <!-- Режим: Лежит дольше N дней -->
 103                    <div class="ocs-filter-field ocs-filter-age-settings ocs-mode-older d-none">
 104                        <label class="form-label" for="ocs-days">Дней на складе, более</label>
 105                        <div class="d-flex flex-wrap align-items-center gap-2">
 106                            <div style="width: 100px;">
 107                                <input id="ocs-days" type="number" min="1" max="3650" value="90" class="form-control for
 108                            </div>
 109                            <div class="ocs-presets btn-group btn-group-sm" role="group">
 110                                <button type="button" class="btn btn-outline-secondary" data-days="10">10 дн.</button>
 111                                <button type="button" class="btn btn-outline-secondary" data-days="20">20 дн.</button>
 112                                <button type="button" class="btn btn-outline-secondary" data-days="30">30 дн.</button>
 113                                <button type="button" class="btn btn-outline-secondary" data-days="90">90 дн.</button>
 114                                <button type="button" class="btn btn-outline-secondary" data-days="180">180 дн.</button>
 115                                <button type="button" class="btn btn-outline-secondary" data-days="365">1 год</button>
 116                                <button type="button" class="btn btn-outline-secondary" data-days="730">2 года</button>
 117                            </div>
 118                        </div>
 119                        <div class="form-text">Строго больше N дней от последней накладной или перемещения на склад: поз
 120                    </div>
 121
 122                    <!-- Режим: Диапазон дат -->
 123                    <div class="ocs-filter-field ocs-filter-age-settings ocs-mode-range d-none">
 124                        <div class="ocs-date-range">
 125                            <div>
 126                                <label class="form-label" for="ocs-from">Приход с</label>
 127                                <input id="ocs-from" type="date" class="form-control form-control-sm" />
 128                            </div>
 129                            <div>
 130                                <label class="form-label" for="ocs-to">по</label>
 131                                <input id="ocs-to" type="date" class="form-control form-control-sm" />
 132                            </div>
 133                            <div>
 134                                <div class="ocs-range-presets btn-group btn-group-sm w-100" role="group">
 135                                    <button type="button" class="btn btn-outline-secondary" data-range-days="30" title="
 136                                    <button type="button" class="btn btn-outline-secondary" data-range-days="90" title="
 137                                    <button type="button" class="btn btn-outline-secondary" data-range-days="180" title=
 138                                    <button type="button" class="btn btn-outline-secondary" data-range-days="365" title=
 139                                </div>
 140                            </div>
 141                        </div>
 142                    </div>
 143                </div>
 144
 145                <!-- Вторая строка фильтров: поиск, источник прихода и представление -->
 146                <div class="ocs-filter-grid">
 147                    <div class="ocs-filter-field">
 148                        <label class="form-label" for="ocs-article">
 149                            <i class="fas fa-barcode text-secondary me-1"></i>Артикул
 150                        </label>
 151                        <input id="ocs-article" class="form-control form-control-sm" placeholder="Поиск по артикулу..." 
 152                    </div>
 153
 154                    <div class="ocs-filter-field">
 155                        <label class="form-label" for="ocs-producer">
 156                            <i class="fas fa-tag text-secondary me-1"></i>Производитель
 157                        </label>
 158                        <input id="ocs-producer" class="form-control form-control-sm" placeholder="Бренд..." autocomplet
 159                    </div>
 160
 161                    <div class="ocs-filter-field">
 162                        <label class="form-label" for="ocs-document-type">
 163                            <i class="fas fa-file-lines text-secondary me-1"></i>Тип документа
 164                        </label>
 165                        <select id="ocs-document-type" class="form-select form-select-sm custom-select-init">
 166                            <option value="all">Все приходы</option>
 167                            <option value="receipt">Приходная накладная</option>
 168                            <option value="transfer">Перемещение запасов</option>
 169                        </select>
 170                    </div>
 171
 172                    <div class="ocs-filter-field">
 173                        <label class="form-label" for="ocs-supplier">
 174                            <i class="fas fa-truck text-secondary me-1"></i>Поставщик
 175                        </label>
 176                        <select id="ocs-supplier" class="form-select form-select-sm custom-select-init">
 177                            <option value="">Все поставщики</option>
 0178                            @foreach (var supplier in pageModel.Suppliers)
 179                            {
 0180                                <option value="@supplier.RefKey">@supplier.Description</option>
 181                            }
 182                        </select>
 183                        <div class="form-text">По последней приходной накладной позиции.</div>
 184                    </div>
 185
 186                    <div class="ocs-filter-field">
 187                        <label class="form-label" for="ocs-minqty">Остаток от</label>
 188                        <input id="ocs-minqty" type="number" min="0" step="1" class="form-control form-control-sm" place
 189                    </div>
 190
 191                    <div class="ocs-filter-field">
 192                        <label class="form-label" for="ocs-pagesize" title="Количество строк, подгружаемых за один шаг п
 193                            Подгружать по
 194                        </label>
 195                        <select id="ocs-pagesize" class="form-select form-select-sm custom-select-init">
 196                            <option value="25">25 строк</option>
 197                            <option value="50" selected>50 строк</option>
 198                            <option value="100">100 строк</option>
 199                        </select>
 200                    </div>
 201
 202                    <div class="ocs-filter-field">
 203                        <label class="form-label" for="ocs-sort-select">Сортировка</label>
 204                        <select id="ocs-sort-select" class="form-select form-select-sm custom-select-init">
 205                            <option value="article:asc" selected>Артикул (А-Я)</option>
 206                            <option value="article:desc">Артикул (Я-А)</option>
 207                            <option value="producer:asc">Производитель (А-Я)</option>
 208                            <option value="producer:desc">Производитель (Я-А)</option>
 209                            <option value="qty:desc">Кол-во (по убыванию)</option>
 210                            <option value="qty:asc">Кол-во (по возрастанию)</option>
 211                            <option value="age:desc">Дней на складе (сначала старые)</option>
 212                            <option value="age:asc">Дней на складе (сначала свежие)</option>
 213                        </select>
 214                    </div>
 215
 216                </div>
 217                <div class="ocs-filter-actions">
 218                    <button type="submit" class="btn btn-primary btn-sm px-3">
 219                        <i class="fas fa-filter me-1"></i>Показать
 220                    </button>
 221                    <button type="button" id="ocs-reset" class="btn btn-outline-secondary btn-sm" title="Сбросить поиско
 222                        <i class="fas fa-rotate-left me-1"></i>Сброс
 223                    </button>
 224                    <button type="button" id="ocs-export" class="btn btn-outline-success btn-sm" title="Скачать все пози
 225                        <i class="fas fa-file-excel me-1"></i>Excel
 226                    </button>
 227                    <button type="button" id="ocs-refresh" class="btn btn-outline-primary btn-sm" title="Очистить кэш ск
 228                        <i class="fas fa-arrows-rotate me-1"></i>Обновить из 1С
 229                    </button>
 230                </div>
 231                <div id="ocs-export-progress" class="ocs-export-progress d-none" aria-live="polite"></div>
 232            </div>
 233        </form>
 234
 235        <div id="ocs-alert" class="alert d-none shadow-sm"></div>
 236
 237        <!-- Таблица остатков -->
 238        <div class="card shadow-sm ocs-table-card">
 239            <div class="card-header py-2 px-3 d-flex flex-wrap align-items-center justify-content-between gap-2">
 240                <div class="d-flex align-items-center gap-2 flex-wrap" id="ocs-active-filters">
 241                    <span class="text-muted small fw-bold text-uppercase"><i class="fas fa-list me-1"></i>Таблица остатк
 242                    <span id="ocs-summary" class="ocs-summary-text small text-secondary"></span>
 243                </div>
 244                <div class="text-muted small" id="ocs-loaded-indicator">
 245                    <!-- Заполняется динамически -->
 246                </div>
 247            </div>
 248            <div class="card-body p-0">
 249                <div id="ocs-table-wrapper" class="table-responsive ocs-table-wrapper" tabindex="0" aria-label="Таблица 
 250                    <table class="table table-sm table-hover align-middle mb-0 ocs-table">
 251                        <thead>
 252                            <tr>
 253                                <th class="text-center ocs-col-image">
 254                                    Фото
 255                                    <span class="th-hint">каталог</span>
 256                                </th>
 257                                <th class="ocs-sortable ocs-col-article" data-sort="article">
 258                                    Артикул
 259                                    <span class="th-hint">клик для копирования</span>
 260                                </th>
 261                                <th class="ocs-col-name">
 262                                    Наименование
 263                                    <span class="th-hint">из карточки 1С</span>
 264                                </th>
 265                                <th class="ocs-sortable ocs-col-producer" data-sort="producer">
 266                                    Производитель
 267                                    <span class="th-hint">OneCNomenclatureMap</span>
 268                                </th>
 269                                <th class="ocs-sortable text-end ocs-col-qty" data-sort="qty">
 270                                    Кол-во
 271                                    <span class="th-hint">остаток</span>
 272                                </th>
 273                                <th class="ocs-col-date">
 274                                    Последний приход
 275                                    <span class="th-hint">дата документа</span>
 276                                </th>
 277                                <th class="ocs-sortable text-end ocs-col-age" data-sort="age" title="От даты последней н
 278                                    Дней на складе
 279                                    <span class="th-hint">давность</span>
 280                                </th>
 281                                <th class="ocs-col-doc">
 282                                    Документ
 283                                    <span class="th-hint">номер и тип</span>
 284                                </th>
 285                                <th class="ocs-col-supplier">
 286                                    Поставщик
 287                                    <span class="th-hint">из прихода 1С</span>
 288                                </th>
 289                                <th class="text-center ocs-col-actions">
 290                                    Движения
 291                                    <span class="th-hint">карта</span>
 292                                </th>
 293                            </tr>
 294                        </thead>
 295                        <tbody id="ocs-rows">
 296                            <tr class="st2-empty-state-row"><td colspan="10"><div class="st2-empty-state"><img class="st
 297                        </tbody>
 298                    </table>
 299
 300                    <!-- Находится внутри прокручиваемого контейнера: наблюдатель видит его при прокрутке таблицы. -->
 301                    <div id="ocs-scroll-sentinel" class="ocs-scroll-sentinel py-3 text-center border-top d-none">
 302                        <div id="ocs-sentinel-loading" class="d-none" aria-live="polite">
 303                            <div class="spinner-border spinner-border-sm text-primary me-2" role="status"></div>
 304                            <span class="text-muted small">Подгрузка следующих позиций…</span>
 305                        </div>
 306                        <div id="ocs-sentinel-more" class="d-none">
 307                            <button type="button" class="btn btn-outline-primary btn-sm px-4" id="ocs-btn-load-more">
 308                                <i class="fas fa-arrow-down me-1"></i>Загрузить следующие позиции
 309                            </button>
 310                        </div>
 311                        <div id="ocs-sentinel-end" class="d-none">
 312                            <span class="badge bg-light text-muted border py-1 px-3">
 313                                <i class="fas fa-check-circle text-success me-1"></i>Все позиции по фильтру загружены
 314                            </span>
 315                        </div>
 316                    </div>
 317                </div>
 318            </div>
 319        </div>
 320    }
 321</div>
 322
 323<!-- Плавающая кнопка «Наверх» -->
 324<button type="button" id="ocs-back-to-top" class="ocs-back-to-top btn btn-primary shadow" title="Наверх">
 325    <i class="fas fa-arrow-up"></i>
 326</button>
 327
 328@section Scripts {
 329    <script src="~/js/Studio2/OneCStock/onec-stock.js" asp-append-version="true"></script>
 330}

Methods/Properties

ExecuteAsync()
<ExecuteAsync()