В стандартном функционале 1С:Предприятие 8.3, включая такие сложные системы, как 1С:ERP или 1С:Комплексная автоматизация, механизм выбора стандартного периода отлично справляется с днями, месяцами и кварталами. Однако задача предоставить пользователю возможность выбрать конкретную неделю года (например, «15-я неделя 2024 года») часто ставит разработчиков в тупик, так как готового виджета для этого в платформе не предусмотрено. В этой статье мы подробно разберем, как реализовать такой функционал самостоятельно, учитывая требования законодательства и удобство интерфейса.
Прежде чем приступать к разработке формы, нам необходимо определиться с тем, что именно мы считаем «первой неделей года». В мировой практике и в 1С существует несколько подходов. Если мы обратимся к функции НеделяГода(), то увидим, что она принимает второй параметр — СпособОпределенияНомераНедели. Рассмотрим это подробнее:
Проанализируем ситуацию: если мы не зафиксируем стандарт определения недели в коде, разные пользователи могут видеть разные данные в отчетах, что недопустимо для систем управленческого учета.
Как справедливо отмечено в обсуждении, наиболее «дружелюбным» решением для пользователя будет создание отдельной формы выбора недели. Разберем по шагам, как её спроектировать.
На форме рекомендуется разместить поле выбора года и список доступных недель. Чтобы пользователь не гадал, какие даты входят в «20-ю неделю», представление в списке должно быть максимально информативным.
Рассмотрим пример кода для заполнения списка недель на форме:
&НаСервере
Процедура ЗаполнитьСписокНедель(ВыбранныйГод)
СписокНедель.Очистить();
// Начинаем с 1 января выбранного года
ТекущаяДата = НачалоГода(Дата(ВыбранныйГод, 1, 1));
КонецГода = КонецГода(ТекущаяДата);
// Цикл по всем неделям года
Пока ТекущаяДата <= КонецГода Цикл
НомерНедели = НеделяГода(ТекущаяДата, СпособОпределенияНомераНедели.ПоЧетвергам);
НачалоНедели = НачалоНедели(ТекущаяДата);
КонецНедели = КонецНедели(ТекущаяДата);
Представление = "Неделя №" + НомерНедели + " (" + Формат(НачалоНедели, "ДФ=dd.MM.yyyy") + " - " + Формат(КонецНедели, "ДФ=dd.MM.yyyy") + ")";
// Добавляем в список значений, где значением будет начало недели
СписокНедель.Добавить(НачалоНедели, Представление);
// Переходим к следующему понедельнику
ТекущаяДата = НачалоНедели + 7 * 24 * 60 * 60;
КонецЦикла;
КонецПроцедуры
Этот подход позволяет пользователю видеть четкие границы периода, что исключает ошибки ввода. Выбранное значение (начало недели) затем легко передать в параметры запроса или в СтандартныйПериод.
Иногда требуется реализовать ввод номера недели напрямую в поле (например, для массового ввода данных). В этом случае нам нужно уметь программно вычислять даты «с... по...», зная только год и номер недели. Выясним причину сложности: 1 января не всегда является понедельником, поэтому простое прибавление (Номер * 7) дней даст неточный результат.
Правильный алгоритм расчета границ недели выглядит следующим образом:
Функция ПолучитьГраницыНедели(Год, НомерНедели) Экспорт
// Находим дату начала года
ДатаНачалаГода = Дата(Год, 1, 1);
// Находим первый четверг года (по ISO 8601 первая неделя та, где первый четверг)
ТекущаяДата = ДатаНачалаГода;
Пока ДеньНедели(ТекущаяДата) <> 4 Цикл
ТекущаяДата = ТекущаяДата + 86400;
КонецЦикла;
// Теперь ТекущаяДата — это четверг 1-й недели.
// Прибавляем нужное количество недель
НужныйЧетверг = ТекущаяДата + (НомерНедели - 1) * 7 * 86400;
Результат = Новый Структура;
Результат.Вставить("ДатаНачала", НачалоНедели(НужныйЧетверг));
Результат.Вставить("ДатаОкончания", КонецНедели(НужныйЧетверг));
Возврат Результат;
КонецФункции
Обратите внимание на проблему 53-й недели. В некоторых годах (например, 2020 или 2026) календарь содержит 53 недели. При программном формировании выбора нельзя жестко ограничивать цикл 52-мя неделями, иначе данные за последние дни года могут не попасть в отчет.
Если ваша задача — сделать выбор недели в отчете на базе Системы компоновки данных (СКД), можно воспользоваться механизмом расширения параметров. Хотя штатный тип СтандартныйПериод не предлагает выбор недели по номеру, мы можем добавить на форму отчета два реквизита: ВыбранныйГод и НомерНедели.
При изменении любого из этих реквизитов мы будем программно устанавливать границы основного параметра периода отчета. Рассмотрим пример обработки события на форме отчета:
&НаКлиенте
Процедура НомерНеделиПриИзменении(Элемент)
Границы = ПолучитьГраницыНеделиНаСервере(Объект.Год, Объект.НомерНедели);
// Устанавливаем период в параметрах СКД
ЗначениеПараметра = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Период"));
Если ЗначениеПараметра <> Неопределено Тогда
ЗначениеПараметра.Значение.Вариант = ВариантСтандартногоПериода.ПроизвольныйПериод;
ЗначениеПараметра.Значение.ДатаНачала = Границы.ДатаНачала;
ЗначениеПараметра.Значение.ДатаОкончания = Границы.ДатаОкончания;
ЗначениеПараметра.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Разберем опыт конфигурации Зарплата и Управление Персоналом. Там выбор месяца реализован через удобную графическую форму. Для выбора недели можно использовать аналогичный подход с использованием ПоляТабличногоДокумента. Мы можем вывести календарную сетку на год, где каждая строка — это неделя. При клике на любую ячейку в строке мы выделяем всю неделю и возвращаем её границы в основную форму.
Важные моменты для реализации в ERP:
НачалоНедели() и КонецНедели() для приведения дат к 00:00:00 и 23:59:59 соответственно.Таким образом, создание собственного механизма выбора недели в 1С:ERP не является сложной задачей, если четко следовать стандартам ISO 8601 и предоставлять пользователю визуальное подтверждение выбранных дат.