< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_TransactionJobs_Create
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/TransactionJobs/Create.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 8
Coverable lines: 8
Total lines: 221
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 34
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%4260%
<ExecuteAsync()0%812280%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/TransactionJobs/Create.cshtml

#LineLine coverage
 1@model OzonDomains.Models.BackgroundJobSchedule
 2@{
 03    ViewData["Title"] = "Создать расписание";
 4}
 5
 6<link rel="stylesheet" href="~/css/Studio2/TransactionJobs/transaction-jobs.css" asp-append-version="true"/>
 7
 8<div class="container py-3 tj-form-page">
 9    <div class="mb-3">
 10        <a asp-action="Index" class="text-muted small text-decoration-none"><i class="fas fa-arrow-left me-1"></i>К спис
 11    </div>
 12    <div class="tj-intro mb-3">
 13        <i class="fas fa-circle-info"></i>
 14        <div class="tj-intro-text">
 15            Новое расписание регистрируется в Hangfire сразу после сохранения. Отчёт Ozon загружается за <strong>вчера</
 16            тип задания определяет, какую транзакцию создавать для подходящих заказов.
 17        </div>
 18    </div>
 19    <div class="row">
 20        <div class="col-lg-10 offset-lg-1">
 21            <div class="card">
 22                <div class="card-header">
 23                    <h3 class="h5 mb-0">
 24                        <i class="fas fa-plus me-2"></i>
 025                        @ViewData["Title"]
 26                    </h3>
 27                </div>
 28                <div class="card-body">
 29                    <form method="post" action="@Url.Action("Create")">
 030                        @Html.AntiForgeryToken()
 31
 32                        <div class="mb-3">
 33                            <label for="Name" class="form-label">Название</label>
 34                            <input type="text" class="form-control" id="Name" name="Name" placeholder="Автоматически сфо
 35                            <div class="form-text">
 36                                <i class="fas fa-magic me-1"></i>Название генерируется автоматически при изменении настр
 37                            </div>
 38                        </div>
 39
 40                        <div class="mb-3">
 41                            <label for="OzonClientId" class="form-label">Ozon Client <span class="text-danger">*</span><
 42                            <select class="form-select" id="OzonClientId" name="OzonClientId" required>
 43                                <option value="">Выберите клиента...</option>
 044                                @foreach (var item in ViewBag.OzonClients)
 45                                {
 046                                    <option value="@item.Value">@item.Text</option>
 47                                }
 48                            </select>
 49                        </div>
 50
 51                        <div class="mb-3">
 52                            <label for="JobType" class="form-label">Тип задания <span class="text-danger">*</span></labe
 53                            <select class="form-select" id="JobType" name="JobType" required>
 54                                <option value="">Выберите тип...</option>
 055                                @foreach (var item in ViewBag.JobTypes)
 56                                {
 057                                    <option value="@item.Value">@item.Text</option>
 58                                }
 59                            </select>
 60                            <div class="form-text mt-2">
 61                                <span class="badge bg-secondary" id="jobTypePreviewBadge">
 62                                    <i class="fas fa-cog me-1"></i>Тип не выбран
 63                                </span>
 64                            </div>
 65                        </div>
 66
 67                        <div class="mb-3">
 68                            <label for="CronExpression" class="form-label">Cron выражение <span class="text-danger">*</s
 69                            <input type="text" class="form-control" id="CronExpression" name="CronExpression" required p
 70                            <div class="form-text">
 71                                <strong>Примеры:</strong><br>
 72                                <code>0 2 * * *</code> - каждый день в 02:00<br>
 73                                <code>0 */6 * * *</code> - каждые 6 часов<br>
 74                                <code>0 0 * * 1</code> - каждый понедельник в 00:00<br>
 75                                <a href="https://crontab.guru/" target="_blank">Проверить выражение</a>
 76                            </div>
 77                        </div>
 78
 79                        <div class="mb-3">
 80                            <label class="form-label">День отбора заказов</label>
 81                            <p class="form-control-plaintext mb-1">
 82                                <strong>Вчера</strong> (календарный день, часовой пояс MSK)
 83                            </p>
 84                            <input type="hidden" name="DaysBack" value="1" />
 85                            <div class="form-text">
 86                                Фиксированное значение: всегда один день — «вчера» относительно момента запуска по Москв
 87                                Изменить период отбора строк в интерфейсе нельзя (как последняя дата в предпросмотре на 
 88                            </div>
 89                        </div>
 90
 091                        @await Html.PartialAsync("_ProcessingPipelineHelp")
 92
 93                        <div class="mb-3 form-check">
 94                            <input type="checkbox" class="form-check-input" id="IsActive" name="IsActive" value="true" c
 95                            <label class="form-check-label" for="IsActive">
 96                                Активировать расписание
 97                            </label>
 98                        </div>
 99
 100                        <div class="d-flex justify-content-between form-actions-sticky">
 101                            <a href="@Url.Action("Index")" class="btn btn-secondary">
 102                                <i class="fas fa-arrow-left me-2"></i>Назад
 103                            </a>
 104                            <button type="submit" class="btn btn-primary">
 105                                <i class="fas fa-save me-2"></i>Сохранить
 106                            </button>
 107                        </div>
 108                    </form>
 109                </div>
 110            </div>
 111        </div>
 112    </div>
 113</div>
 114
 115@section Scripts {
 116<script>
 117    $(document).ready(function() {
 118        // Auto-generate name based on settings
 119        function generateName() {
 120            const clientId = $('#OzonClientId').val();
 121            const clientText = $('#OzonClientId option:selected').text();
 122            const jobType = $('#JobType').val();
 123            const jobTypeText = $('#JobType option:selected').text();
 124            const cronExpr = $('#CronExpression').val().trim();
 125            if (!clientId || !jobType || !cronExpr) {
 126                return '';
 127            }
 128
 129            const cronDesc = parseCronExpression(cronExpr);
 130            const periodText = 'за вчера';
 131
 132            // Build name
 133            const name = `${jobTypeText} ${periodText} для ${clientText} (${cronDesc})`;
 134            return name;
 135        }
 136
 137        function parseCronExpression(cron) {
 138            if (!cron) return '';
 139
 140            const parts = cron.split(' ').filter(p => p.length > 0);
 141            if (parts.length < 5) return cron;
 142
 143            const [minute, hour, dayOfMonth, month, dayOfWeek] = parts;
 144
 145            // Daily patterns
 146            if (dayOfMonth === '*' && month === '*' && dayOfWeek === '*') {
 147                if (hour.startsWith('*/')) {
 148                    const hourInterval = hour.substring(2);
 149                    return `каждые ${hourInterval}ч`;
 150                } else if (hour !== '*') {
 151                    return `ежедневно в ${hour.padStart(2, '0')}:${minute.padStart(2, '0')}`;
 152                } else {
 153                    return 'каждый час';
 154                }
 155            }
 156
 157            // Weekly patterns
 158            if (dayOfWeek !== '*' && dayOfMonth === '*') {
 159                const dayNames = ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'];
 160                const dayName = dayNames[parseInt(dayOfWeek)] || dayOfWeek;
 161                return `${dayName} в ${hour.padStart(2, '0')}:${minute.padStart(2, '0')}`;
 162            }
 163
 164            // Monthly patterns
 165            if (dayOfMonth !== '*' && month === '*') {
 166                return `${dayOfMonth}-го числа в ${hour.padStart(2, '0')}:${minute.padStart(2, '0')}`;
 167            }
 168
 169            return cron;
 170        }
 171
 172        function updateName() {
 173            const currentName = $('#Name').val();
 174            const newName = generateName();
 175
 176            // Only update if field is empty or contains auto-generated name
 177            if (!currentName || currentName.includes('для ') || currentName === '') {
 178                $('#Name').val(newName);
 179            }
 180        }
 181
 182        function updateJobTypePreview() {
 183            const value = $('#JobType').val();
 184            const badge = $('#jobTypePreviewBadge');
 185            badge.removeClass('bg-secondary bg-primary bg-warning text-dark bg-success');
 186
 187            $('.job-type-help').addClass('d-none');
 188            $('.job-help-commissioner, .job-help-return').addClass('d-none');
 189            $('#helpJobTypePlaceholder').removeClass('d-none');
 190
 191            if (value === 'ShippedToCommissioner') {
 192                badge.addClass('bg-primary').html('<i class="fas fa-truck-loading me-1"></i>Отгружен комиссионеру');
 193                $('#helpShippedToCommissioner').removeClass('d-none');
 194                $('.job-help-commissioner').removeClass('d-none');
 195                $('#helpJobTypePlaceholder').addClass('d-none');
 196                return;
 197            }
 198
 199            if (value === 'CustomerReturn') {
 200                badge.addClass('bg-warning text-dark').html('<i class="fas fa-undo-alt me-1"></i>Возврат покупателя');
 201                $('#helpCustomerReturn').removeClass('d-none');
 202                $('.job-help-return').removeClass('d-none');
 203                $('#helpJobTypePlaceholder').addClass('d-none');
 204                return;
 205            }
 206
 207            badge.addClass('bg-secondary').html('<i class="fas fa-cog me-1"></i>Тип не выбран');
 208        }
 209
 210        // Trigger auto-generation on field changes
 211        $('#OzonClientId, #JobType, #CronExpression').on('change input', function() {
 212            updateName();
 213            updateJobTypePreview();
 214        });
 215
 216        // Initial generation on page load
 217        updateName();
 218        updateJobTypePreview();
 219    });
 220</script>
 221}

Methods/Properties

ExecuteAsync()
<ExecuteAsync()