< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_AssemblyList_HistoryDetail
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/AssemblyList/HistoryDetail.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 49
Coverable lines: 49
Total lines: 273
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 62
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%3906620%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/AssemblyList/HistoryDetail.cshtml

#LineLine coverage
 1@model List<OzonDomains.Models.AssemblyListRunItem>
 2@{
 03    ViewData["Title"] = $"Лист подбора #{ViewBag.RunId}";
 04    var run = (OzonDomains.Models.AssemblyListRun)ViewBag.Run;
 5}
 6
 7<link rel="stylesheet" href="~/css/Studio2/OzonClients/ozon-clients-form.css" asp-append-version="true" />
 8
 9@section HeaderActions {
 10<div class="header-page-actions">
 11    <span class="header-page-actions-sep"></span>
 12    <div class="btn-group">
 13        <a href="/Studio2/AssemblyList/History" class="hpa-btn">
 14            <i class="fas fa-arrow-left"></i><span class="hpa-label">История</span>
 15        </a>
 16    </div>
 17    <div class="btn-group">
 18        <a href="/Studio2/AssemblyList/DownloadHistoryExcel?runId=@ViewBag.RunId" class="hpa-btn">
 19            <i class="fas fa-file-excel text-success"></i><span class="hpa-label">Excel</span>
 20        </a>
 21    </div>
 22    <div class="btn-group">
 23        <a href="/Studio2/AssemblyList/DownloadHistoryPdf?runId=@ViewBag.RunId" class="hpa-btn">
 24            <i class="fas fa-file-pdf text-danger"></i><span class="hpa-label">PDF</span>
 25        </a>
 26    </div>
 27    <div class="btn-group">
 28        <button type="button" class="hpa-btn" onclick="openAllLabels()">
 29            <i class="fas fa-tags text-warning"></i><span class="hpa-label">Этикетки</span>
 30        </button>
 31    </div>
 32</div>
 33}
 34
 35<div class="container-fluid py-3">
 36
 37    <div class="oc-form-hero">
 038        <h1><i class="fas fa-list-alt me-2 text-primary"></i>Лист подбора #@ViewBag.RunId</h1>
 039        @if (run != null)
 40        {
 41            <div class="subtitle-help">
 042                Клиент: <strong>@run.OzonClientName</strong>
 043                &nbsp;·&nbsp; Период: @run.CutoffFrom.ToString("dd.MM.yyyy") – @run.CutoffTo.ToString("dd.MM.yyyy")
 044                &nbsp;·&nbsp; Сформирован: @run.StartedAtUtc.ToLocalTime().ToString("dd.MM.yyyy HH:mm")
 045                &nbsp;·&nbsp; Позиций: <strong>@Model.Count</strong>
 46            </div>
 47        }
 48    </div>
 49
 50    <div class="oc-form-card p-0">
 51        <div class="oc-form-card-header px-3 pt-3 pb-2">
 52            <h2><i class="fas fa-list-alt text-muted me-2"></i>Позиции</h2>
 53            <div class="d-flex gap-2 align-items-center">
 054                <span class="badge bg-primary">@Model.Count строк</span>
 55                <a href="/Studio2/AssemblyList/DownloadHistoryExcel?runId=@ViewBag.RunId"
 56                   class="btn btn-sm btn-outline-success">
 57                    <i class="fas fa-file-excel me-1"></i>Excel
 58                </a>
 59                <a href="/Studio2/AssemblyList/DownloadHistoryPdf?runId=@ViewBag.RunId"
 60                   class="btn btn-sm btn-outline-danger">
 61                    <i class="fas fa-file-pdf me-1"></i>PDF
 62                </a>
 63            </div>
 64        </div>
 65        <div class="table-responsive">
 66            <table class="table table-sm table-hover align-middle mb-0" id="historyDetailTable">
 67                <thead class="table-light">
 68                    <tr>
 69                        <th class="text-center" style="width:40px;">№</th>
 70                        <th>Отправление</th>
 71                        <th>Артикул</th>
 72                        <th>Название</th>
 73                        <th>Склад</th>
 74                        <th>Статус</th>
 75                        <th class="text-center" style="width:60px;">Кол-во</th>
 76                        <th>Поставщик</th>
 77                        <th>Заказан поставщику</th>
 78                        <th class="text-center text-nowrap">Остаток 1С</th>
 79                        <th>Документ 1С</th>
 80                        <th>Этикетка</th>
 81                    </tr>
 82                </thead>
 83                <tbody>
 84                    @{
 085                        string lastPosting = "";
 86                    }
 087                    @foreach (var item in Model)
 88                    {
 089                        var borderTop = item.PostingNumber != lastPosting ? "border-top: 2px solid #dee2e6;" : "";
 090                        lastPosting = item.PostingNumber;
 91
 092                        var statusClass = item.Status switch
 093                        {
 094                            "awaiting_deliver"   => "bg-primary",
 095                            "awaiting_packaging" => "bg-warning text-dark",
 096                            "delivering"         => "bg-info text-dark",
 097                            "cancelled"          => "bg-danger",
 098                            "not_accepted"       => "bg-danger",
 099                            _                    => "bg-secondary",
 0100                        };
 101
 0102                        var movArticle = item.OfferId.Contains('=') ? item.OfferId[..item.OfferId.IndexOf('=')] : item.O
 0103                        var movUrl = "/Studio2/WarehouseStock/movement-map?article=" + Uri.EscapeDataString(movArticle);
 104
 105                        <tr style="@borderTop">
 0106                            <td class="text-center text-muted small">@item.ItemIndex</td>
 107                            <td class="text-nowrap">
 108                                <code class="small copy-value" onclick="copyArticle(this)"
 0109                                      role="button" title="Нажмите, чтобы скопировать">@item.PostingNumber</code>
 110                            </td>
 111                            <td>
 112                                <code class="small copy-value" onclick="copyArticle(this)"
 0113                                      role="button" title="Нажмите, чтобы скопировать">@item.OfferId</code>
 114                            </td>
 115                            <td class="small">
 116                                <div class="d-flex align-items-center gap-2">
 0117                                    @if (!string.IsNullOrEmpty(item.ImageUrl))
 118                                    {
 119                                        <img src="/Studio2/AssemblyList/ImageProxy?url=@Uri.EscapeDataString(item.ImageU
 120                                             class="assembly-table-img flex-shrink-0" loading="lazy"
 121                                             onerror="this.parentNode.innerHTML=''" />
 122                                    }
 0123                                    <span>@item.ProductName</span>
 124                                </div>
 125                            </td>
 0126                            <td class="small text-nowrap">@item.WarehouseName</td>
 0127                            <td><span class="badge @statusClass" style="font-size:0.72rem;">@item.StatusLabel</span></td
 0128                            <td class="text-center fw-bold">@item.Quantity</td>
 0129                            <td class="small text-nowrap">@(item.SupplierName ?? "—")</td>
 130                            <td class="small text-nowrap">
 0131                                @(item.OrderedToSupplierDate.HasValue
 0132                                    ? item.OrderedToSupplierDate.Value.ToLocalTime().ToString("dd.MM.yyyy HH:mm")
 0133                                    : "—")
 134                            </td>
 135                            <td class="text-center small text-nowrap">
 136                                <a href="@movUrl" target="_blank" class="text-decoration-none d-inline-block">
 0137                                    @if (item.OneCBalance.HasValue)
 138                                    {
 0139                                        if (item.OneCBalance.Value > 0)
 140                                        {
 0141                                            <span class="text-success fw-bold">@item.OneCBalance.Value.ToString("0.###")
 142                                        }
 143                                        else
 144                                        {
 145                                            <span class="text-danger fw-bold">0</span>
 0146                                            @if (!string.IsNullOrEmpty(item.OneCOtherStock))
 147                                            {
 0148                                                foreach (var stockPart in item.OneCOtherStock.Split(',', StringSplitOpti
 149                                                {
 0150                                                    <br /><span class="text-muted text-nowrap" style="font-size:0.8em;">
 151                                                }
 152                                            }
 153                                        }
 154                                    }
 155                                    else
 156                                    {
 157                                        <span class="text-muted">—</span>
 158                                    }
 159                                </a>
 160                            </td>
 161                            <td class="small text-nowrap">
 0162                                @if (item.OneCReceiptDocKey.HasValue && !string.IsNullOrEmpty(item.OneCReceiptDoc))
 163                                {
 164                                    <a href="/Studio2/OneCDocument/Details?refKey=@item.OneCReceiptDocKey.Value" target=
 0165                                        @item.OneCReceiptDoc
 166                                    </a>
 167                                }
 168                                else
 169                                {
 0170                                    @(item.OneCReceiptDoc ?? "—")
 171                                }
 172                            </td>
 173                            <td style="width:70px;">
 0174                                @if (!string.IsNullOrEmpty(item.LabelUrl))
 175                                {
 0176                                    var proxyUrl = "/Studio2/AssemblyList/LabelProxy?url=" + Uri.EscapeDataString(item.L
 177                                    <a href="@proxyUrl" download class="label-thumb-link" title="Скачать этикетку">
 0178                                        <canvas class="label-thumb" data-pdf="@proxyUrl"></canvas>
 179                                    </a>
 180                                }
 0181                                else if (!string.IsNullOrEmpty(item.LabelError))
 182                                {
 183                                    <span class="text-muted small" title="@item.LabelError">
 184                                        <i class="fas fa-exclamation-triangle text-danger"></i>
 185                                    </span>
 186                                }
 187                                else
 188                                {
 189                                    <span class="text-muted">—</span>
 190                                }
 191                            </td>
 192                        </tr>
 193                    }
 194                </tbody>
 195            </table>
 196        </div>
 197    </div>
 198</div>
 199
 200@section Scripts {
 201<style>
 202.assembly-table-img {
 203    width: 48px; height: 48px;
 204    object-fit: contain;
 205    border-radius: 4px;
 206    border: 1px solid #dee2e6;
 207    background: #f8f9fa;
 208}
 209.label-thumb {
 210    display: block;
 211    max-width: 72px; max-height: 108px;
 212    width: auto; height: auto;
 213    border: 1px solid #dee2e6;
 214    border-radius: 3px;
 215    cursor: pointer;
 216    background: #f8f9fa;
 217    transition: box-shadow .15s;
 218}
 219.label-thumb-link:hover .label-thumb { box-shadow: 0 0 0 2px #ffc107; }
 220.copy-value { cursor: pointer; }
 221.copy-value:hover { background: #fff3cd; border-radius: 3px; }
 222.copy-value.copied { background: #d1e7dd; border-radius: 3px; }
 223</style>
 224<script src="~/js/copyArticle.js" asp-append-version="true"></script>
 225<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js" crossorigin="anonymous"></script>
 226<script>
 227pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
 228document.querySelectorAll('canvas.label-thumb').forEach(renderLabelThumb);
 229
 230function renderLabelThumb(canvas) {
 231    if (!canvas) return;
 232    pdfjsLib.getDocument(canvas.dataset.pdf).promise.then(function (pdf) {
 233        return pdf.getPage(1);
 234    }).then(function (page) {
 235        var vp = page.getViewport({ scale: 1 });
 236        var scale = Math.min(72 / vp.width, 108 / vp.height);
 237        var viewport = page.getViewport({ scale: scale });
 238        canvas.width = viewport.width;
 239        canvas.height = viewport.height;
 240        page.render({ canvasContext: canvas.getContext('2d'), viewport: viewport });
 241    }).catch(function () {
 242        canvas.width = 58; canvas.height = 20;
 243        var ctx = canvas.getContext('2d');
 244        ctx.fillStyle = '#fff3cd'; ctx.fillRect(0, 0, 58, 20);
 245        ctx.fillStyle = '#856404'; ctx.font = '10px sans-serif';
 246        ctx.textAlign = 'center'; ctx.fillText('PDF', 29, 14);
 247    });
 248}
 249
 250function openAllLabels() {
 251    document.querySelectorAll('.label-thumb-link').forEach(function (a) { a.click(); });
 252}
 253
 254function showNotification(message, type) {
 255    type = type || 'success';
 256    var container = document.getElementById('notification-container');
 257    if (!container) {
 258        container = document.createElement('div');
 259        container.id = 'notification-container';
 260        container.style.cssText = 'position:fixed;top:20px;right:20px;z-index:99999;display:flex;flex-direction:column;g
 261        document.body.appendChild(container);
 262    }
 263    var cls = type === 'success' ? 'alert-success' : type === 'error' ? 'alert-danger' : 'alert-warning';
 264    var toast = document.createElement('div');
 265    toast.className = 'alert ' + cls + ' alert-dismissible fade show';
 266    toast.style.cssText = 'min-width:220px;max-width:350px;box-shadow:0 0.5rem 1rem rgba(0,0,0,.15);';
 267    toast.innerHTML = message + '<button type="button" class="btn-close" data-bs-dismiss="alert"></button>';
 268    container.appendChild(toast);
 269    var bsAlert = new bootstrap.Alert(toast);
 270    setTimeout(function () { if (toast.parentNode) bsAlert.close(); }, 2000);
 271}
 272</script>
 273}

Methods/Properties

ExecuteAsync()