< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_OzonClients_Edit
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OzonClients/Edit.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 48
Coverable lines: 48
Total lines: 321
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 190
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%109201040%
<ExecuteAsync()0%6806820%
<ExecuteAsync()0%2040%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/OzonClients/Edit.cshtml

#LineLine coverage
 1@using OzonOrdersWeb.ViewModels.OzonClientViewModels
 2@model EditOzonClientViewModel
 3@{
 04    var model = Model!;
 5}
 6@{
 07    ViewData["Title"] = $"Редактирование клиента — {Model?.OzonClient?.Name ?? Model?.OzonClient?.Id.ToString() ?? "N/A"
 08    Layout = "~/Views/Shared/_Layout.cshtml";
 09    var status = (string?)ViewData["EditInfo"];
 010    var clientName = Model?.OzonClient?.Name ?? $"ID {Model?.OzonClient?.Id}";
 11}
 12
 13<link rel="stylesheet" href="~/css/Studio2/OzonClients/ozon-clients-form.css" asp-append-version="true"/>
 14
 015@await Html.PartialAsync("_BsxGridShell")
 16
 17<div class="container py-3 oc-form-page bsx-surface">
 18    <div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
 19        <a asp-action="Index" class="oc-form-back">
 20            <i class="fas fa-arrow-left"></i>К списку клиентов
 21        </a>
 022        <span class="text-muted small">ID #@(model.OzonClient.Id)</span>
 23    </div>
 24
 25    <div class="oc-form-hero">
 26        <h1><i class="fas fa-pencil-alt me-2 text-primary"></i>Редактирование клиента</h1>
 027        <div class="subtitle">@clientName</div>
 28        <div class="subtitle-help">
 29            Здесь меняются API-ключи и справочные поля. На странице списка доступно быстрое редактирование
 30            названия, валюты и ИНН — API Key меняется только здесь. Ниже — диагностика Ozon API (роли, данные продавца).
 31        </div>
 32    </div>
 33
 034    @if (status != null)
 35    {
 36        <div class="alert alert-danger alert-dismissible fade show mb-3" role="alert">
 037            <i class="fas fa-exclamation-circle me-2"></i>@status
 38            <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Закрыть"></button>
 39        </div>
 40    }
 41
 42    <div class="oc-form-card">
 43        <div class="oc-intro">
 44            <i class="fas fa-circle-info"></i>
 45            <div class="oc-intro-text">
 46                После смены <strong>Client ID / API Key</strong> проверьте блок «Роли и разрешения API» ниже —
 47                если ключ невалиден, фоновые задания и загрузка отчётов для этого клиента перестанут работать.
 48                ИНН должен совпадать с контрагентом в 1С для корректных проводок.
 49            </div>
 50        </div>
 51
 52        <form id="ozonClientEditForm" asp-area="Studio2" asp-controller="OzonClients" asp-action="Edit" method="post">
 53            <div asp-validation-summary="ModelOnly" class="text-danger small mb-2"></div>
 54            <input type="hidden" asp-for="OzonClient.Id"/>
 55
 56            <div class="oc-form-section">
 57                <div class="oc-form-card-header">
 58                    <h2><i class="fas fa-user me-2 text-muted"></i>Основные данные</h2>
 59                </div>
 60                <div class="oc-form-grid">
 61                    <div>
 62                        <label asp-for="OzonClient.Name" class="form-label">Название<span class="oc-required-mark">*</sp
 63                        <input asp-for="OzonClient.Name" class="form-control form-control-sm"/>
 64                        <div class="oc-field-hint">Отображается в заказах и фильтрах Studio2.</div>
 65                        <span asp-validation-for="OzonClient.Name" class="text-danger small"></span>
 66                    </div>
 67                    <div>
 68                        <label asp-for="OzonClient.ClientType" class="form-label">Тип клиента</label>
 69                        <select asp-for="OzonClient.ClientType" class="form-select form-select-sm">
 70                            <option value="ALL">Другое</option>
 71                            <option value="OZON">Ozon</option>
 72                            <option value="YANDEX">Yandex</option>
 73                        </select>
 74                        <div class="oc-field-hint">Определяет, какой API используется для интеграции и диагностики ниже.
 75                        <span asp-validation-for="OzonClient.ClientType" class="text-danger small"></span>
 76                    </div>
 77                    <div>
 78                        <label asp-for="OzonClient.CurrencyCode" class="form-label">Валюта отчётов</label>
 79                        <select asp-for="OzonClient.CurrencyCode" class="form-select form-select-sm">
 80                            <option value="RUB">RUB</option>
 81                            <option value="USD">USD</option>
 82                            <option value="EUR">EUR</option>
 83                            <option value="BYN">BYN</option>
 84                        </select>
 85                        <div class="oc-field-hint">Валюта цен в отчётах маркетплейса для пересчёта в рубли.</div>
 86                        <span asp-validation-for="OzonClient.CurrencyCode" class="text-danger small"></span>
 87                    </div>
 88                    <div>
 89                        <label asp-for="OzonClient.INNCode" class="form-label">ИНН юрлица</label>
 90                        <div class="oc-inn-search">
 91                            <input type="text" class="form-control form-control-sm" id="supplierSearch"
 92                                   placeholder="ИНН или название компании…" autocomplete="off"/>
 93                            <input type="hidden" asp-for="OzonClient.INNCode" id="innInput"/>
 94                            <div class="oc-inn-results inn-ac-results" id="supplierResults"></div>
 95                        </div>
 96                        <div class="oc-field-hint">Контрагент в 1С — в списке клиентов под ИНН показывается результат по
 97                        <span asp-validation-for="OzonClient.INNCode" class="text-danger small"></span>
 98                    </div>
 99                    <div>
 100                        <label asp-for="OzonClient.WarehouseName" class="form-label">Склад Bitrix (1С)</label>
 101                        <select asp-for="OzonClient.WarehouseName" class="form-select form-select-sm" asp-items="model.B
 102                            <option value="">Выберите склад…</option>
 103                        </select>
 104                        <div class="oc-field-hint">Склад 1С по умолчанию для документов. Маппинг складов Ozon — в <a asp
 105                        <span asp-validation-for="OzonClient.WarehouseName" class="text-danger small"></span>
 106                    </div>
 107                </div>
 108            </div>
 109
 0110            @if (model.OzonClient.ApiKey != null && model.OzonClient.ClientId != null)
 111            {
 112                <div class="oc-form-section oc-form-section--muted">
 113                    <div class="oc-form-card-header border-0 pb-2 mb-2">
 114                        <h2><i class="fas fa-key me-2 text-muted"></i>Данные для API</h2>
 115                    </div>
 116                    <div class="oc-form-grid">
 117                        <div class="oc-field-mono">
 118                            <label asp-for="OzonClient.ClientId" class="form-label">Client ID</label>
 119                            <div class="input-group input-group-sm oc-input-actions">
 120                                <input asp-for="OzonClient.ClientId" id="clientIdInput"
 0121                                       value="@(model.OzonClient.DecryptClientId)" class="form-control"/>
 122                                <button class="btn btn-outline-secondary" type="button"
 123                                        id="copyClientIdBtn" title="Копировать Client ID">
 124                                    <i class="fas fa-copy"></i>
 125                                </button>
 126                            </div>
 127                            <div class="oc-field-hint">Идентификатор продавца в Ozon Seller API (заголовок Client-Id).</
 128                            <span asp-validation-for="OzonClient.ClientId" class="text-danger small"></span>
 129                        </div>
 130                        <div class="oc-field-mono">
 131                            <label asp-for="OzonClient.ApiKey" class="form-label">API Key</label>
 132                            <div class="input-group input-group-sm oc-input-actions">
 133                                <input asp-for="OzonClient.ApiKey" id="apiKeyInput" type="password"
 0134                                       value="@(model.OzonClient.DecryptApiKey)" class="form-control"/>
 135                                <button class="btn btn-outline-secondary" type="button"
 136                                        id="copyApiKeyBtn" title="Копировать API Key">
 137                                    <i class="fas fa-copy"></i>
 138                                </button>
 139                                <button class="btn btn-outline-secondary" type="button"
 140                                        id="togglePassword" title="Показать/скрыть">
 141                                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
 142                                         fill="currentColor" class="bi bi-eye-fill" viewBox="0 0 16 16">
 143                                        <path d="M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0"/>
 144                                        <path d="M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8m8 3.5a3.5 3.5 0 1 0 0-7
 145                                    </svg>
 146                                </button>
 147                            </div>
 148                            <div class="oc-field-hint">Секретный ключ API. При сохранении шифруется в БД. Оставьте без и
 149                            <span asp-validation-for="OzonClient.ApiKey" class="text-danger small"></span>
 150                        </div>
 151                    </div>
 152                </div>
 153            }
 154
 155            <div class="d-none">
 156                <input asp-for="OzonClient.DecryptApiKey"/>
 157                <input asp-for="OzonClient.DecryptClientId"/>
 158            </div>
 159
 160            <div class="oc-form-actions">
 161                <button type="submit" class="btn btn-primary btn-sm">
 162                    <i class="fas fa-save me-1"></i>Сохранить
 163                </button>
 164                <a asp-action="Index" class="btn btn-outline-secondary btn-sm">
 165                    <i class="fas fa-arrow-left me-1"></i>К списку
 166                </a>
 167            </div>
 168        </form>
 169    </div>
 170
 0171    @if (model.HasSellerInfo && model.SellerInfo != null)
 172    {
 173        <div class="oc-form-card">
 174            <div class="oc-form-card-header">
 175                <h2><i class="fas fa-store me-2 text-muted"></i>Информация о продавце Ozon</h2>
 176                <span class="badge bg-info">Данные получены</span>
 177            </div>
 178            <div class="oc-info-grid">
 0179                @if (model.SellerInfo?.Company != null)
 180                {
 181                    <div class="oc-info-card">
 182                        <div class="oc-info-card-title">Компания</div>
 0183                        <div class="oc-info-row"><span class="oc-info-label">Название:</span>@(model.SellerInfo!.Company
 0184                        <div class="oc-info-row"><span class="oc-info-label">Юр. название:</span>@(model.SellerInfo.Comp
 0185                        <div class="oc-info-row"><span class="oc-info-label">ИНН:</span>@(model.SellerInfo.Company.Inn ?
 0186                        <div class="oc-info-row"><span class="oc-info-label">ОГРН:</span>@(model.SellerInfo.Company.Ogrn
 0187                        <div class="oc-info-row"><span class="oc-info-label">Страна:</span>@(model.SellerInfo.Company.Co
 0188                        <div class="oc-info-row"><span class="oc-info-label">Валюта:</span>@(model.SellerInfo.Company.Cu
 0189                        <div class="oc-info-row"><span class="oc-info-label">Форма:</span>@(model.SellerInfo.Company.Own
 0190                        <div class="oc-info-row"><span class="oc-info-label">Налоги:</span>@(model.SellerInfo.Company.Ta
 191                    </div>
 192                }
 0193                @if (model.SellerInfo?.Subscription != null)
 194                {
 0195                    var subscription = model.SellerInfo!.Subscription!;
 196                    <div class="oc-info-card">
 197                        <div class="oc-info-card-title">Подписка</div>
 198                        <div class="oc-info-row">
 199                            <span class="oc-info-label">Тип:</span>
 0200                            <span class="text-primary fw-semibold">@(subscription.Type ?? "UNKNOWN")</span>
 201                        </div>
 202                        <div class="oc-info-row">
 203                            <span class="oc-info-label">Premium:</span>
 0204                            @if (subscription.IsPremium)
 205                            {
 206                                <span class="badge bg-success">Да</span>
 207                            }
 208                            else
 209                            {
 210                                <span class="badge bg-secondary">Нет</span>
 211                            }
 212                        </div>
 213                    </div>
 214                }
 215            </div>
 0216            @if (model.SellerInfo?.Ratings != null && model.SellerInfo.Ratings.Any())
 217            {
 0218                var sellerRatings = model.SellerInfo.Ratings;
 219                <div class="mt-3 pt-3 border-top">
 220                    <div class="oc-form-card-header border-0 pt-0">
 221                        <h2>Рейтинги продавца</h2>
 222                    </div>
 223                    <div class="oc-role-grid">
 0224                        @foreach (var rating in sellerRatings)
 225                        {
 226                            <div class="oc-rating-card">
 227                                <div class="oc-rating-header">
 0228                                    <div class="oc-rating-name">@(rating.Name ?? rating.RatingName ?? "Рейтинг")</div>
 0229                                    @if (!string.IsNullOrEmpty(rating.Status))
 230                                    {
 0231                                        <span class="oc-rating-status status-@rating.Status.ToLower()">@rating.Status</s
 232                                    }
 233                                </div>
 0234                                @if (rating.CurrentValue != null)
 235                                {
 236                                    <div class="oc-info-row">
 237                                        <span class="oc-info-label">Сейчас:</span>
 0238                                        @(rating.CurrentValue.Formatted ?? rating.CurrentValue.Value.ToString("F2"))
 239                                    </div>
 0240                                    @if (rating.PastValue != null)
 241                                    {
 242                                        <div class="oc-info-row text-muted">
 243                                            <span class="oc-info-label">Было:</span>
 0244                                            @(rating.PastValue.Formatted ?? rating.PastValue.Value.ToString("F2"))
 245                                        </div>
 246                                    }
 247                                }
 0248                                @if (!string.IsNullOrEmpty(rating.ValueType))
 249                                {
 0250                                    <div class="small text-muted">Тип: @rating.ValueType</div>
 251                                }
 252                            </div>
 253                        }
 254                    </div>
 255                </div>
 256            }
 257        </div>
 258    }
 259
 260    <div class="oc-form-card">
 261        <div class="oc-form-card-header">
 262            <h2><i class="fas fa-shield-alt me-2 text-muted"></i>Роли и разрешения API</h2>
 0263            @if (model.ApiRoles != null && model.ApiRoles.Any())
 264            {
 0265                @if (model.HasApiAccess)
 266                {
 267                    <span class="badge bg-success">API доступен</span>
 268                }
 269                else
 270                {
 271                    <span class="badge bg-warning text-dark">Ошибка доступа</span>
 272                }
 273            }
 274        </div>
 0275        @if (model.ApiRoles != null && model.ApiRoles.Any())
 276        {
 277            <div class="oc-role-grid">
 0278                @foreach (var role in model.ApiRoles)
 279                {
 280                    <div class="oc-role-card">
 0281                        <div class="oc-role-name">@role.Name</div>
 0282                        @if (role.Methods != null && role.Methods.Any())
 283                        {
 284                            <ul class="oc-method-list">
 0285                                @foreach (var method in role.Methods)
 286                                {
 0287                                    <li class="oc-method-item">@method</li>
 288                                }
 289                            </ul>
 290                        }
 291                        else
 292                        {
 293                            <p class="oc-empty-hint">Нет доступных методов</p>
 294                        }
 295                    </div>
 296                }
 297            </div>
 298        }
 299        else
 300        {
 301            <p class="oc-empty-hint">Роли API не загружены — проверьте Client ID и API Key, либо клиент не является Ozon
 302        }
 303    </div>
 304</div>
 305
 306@section Scripts {
 0307    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
 308    <script src="~/js/inn-autocomplete.js" asp-append-version="true"></script>
 309    <script src="~/js/Studio2/OzonClients/form.js" asp-append-version="true"></script>
 310    <script>
 311        document.addEventListener('DOMContentLoaded', function () {
 312            window.innAutocomplete({
 313                searchInputId: 'supplierSearch',
 314                hiddenInputId: 'innInput',
 315                resultsId: 'supplierResults',
 316                endpoint: '/Studio2/OzonClients/SearchCounterparties'
 317            });
 318            window.OzonClientForm.initEdit();
 319        });
 320    </script>
 321}