В процессе разработки интерфейсов на платформе 1С:Предприятие 8.3 часто возникает специфическая задача: необходимо, чтобы пользователь вводил не полную дату (день, месяц, год), а только конкретный год. При этом в базе данных информация может храниться как тип Дата (обычно начало года) или как Число. Рассмотрим подробно все существующие методы решения этой задачи, проанализируем их плюсы и минусы, а также разберем программный код для реализации каждого подхода.
Самый простой путь, который часто первым приходит в голову — это использование встроенных возможностей оформления элементов формы. Если наш реквизит имеет тип Дата, мы можем попытаться ограничить его отображение только годом. Для интерактивной проверки и настройки свойств элементов формы в пользовательском сеансе подойдёт обработка для редактирования свойств элементов открытых форм.
Разберем по шагам, как это настроить в конфигураторе:
ДФ=гггг. Это обеспечит корректное отображение (например, «2023» вместо «01.01.2023»).ДФ=гггг.Проанализируем ситуацию: на первый взгляд, решение идеально. Однако у него есть существенный недостаток. При нажатии на кнопку выбора (три точки) пользователю все равно откроется стандартный календарь. Даже если пользователь выберет 15 мая, в поле отобразится только год, но сам факт открытия календаря для выбора года крайне неудобен. Чтобы минимизировать это, рекомендуется в свойствах поля ввода установить флаг КнопкаВыбора = Нет. В этом случае пользователь сможет вводить цифры года только с клавиатуры.
Если диапазон лет, доступных для выбора, ограничен (например, текущий год плюс-минус 5 лет), мы можем предложить пользователю выбор из выпадающего списка. Это значительно ускоряет работу и исключает ошибки ввода.
Для реализации этого метода выполним следующие действия:
РежимВыбораИзСписка в значение Истина.ПриСозданииНаСервере, программно заполним этот список.
Рассмотрим пример кода:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Определяем диапазон лет
ТекущийГод = Год(ТекущаяДата());
Для текГод = (ТекущийГод - 10) По (ТекущийГод + 1) Цикл
// Добавляем значение: сама дата на начало года и представление в виде строки
Элементы.ПериодГод.СписокВыбора.Добавить(Дата(текГод, 1, 1), Строка(текГод));
КонецЦикла;
КонецПроцедуры
В этом случае в базе данных по-прежнему хранится полноценная Дата, но интерфейс становится максимально дружелюбным: пользователь просто выбирает нужный год из списка.
Как отмечали участники обсуждения на форуме, наиболее надежный и гибкий метод — это разделение хранения данных и их представления. Мы создаем на форме реквизит с типом Число (длина 4, точность 0), а в объекте (документе или справочнике) оставляем реквизит Дата.
Выясним причину, почему это лучше: числовое поле позволяет легко использовать кнопки регулирования (стрелочки вверх/вниз), маски ввода и не провоцирует систему на вызов календаря.
Рассмотрим алгоритм реализации:
ГодЧислом (тип Число).КнопкаРегулирования = Истина.Для синхронизации нам понадобится написать код в событиях формы:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Извлекаем год из даты объекта при открытии формы
Если ЗначениеЗаполнено(Объект.ДатаПериода) Тогда
ГодЧислом = Год(Объект.ДатаПериода);
Иначе
ГодЧислом = Год(ТекущаяДата());
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Записываем дату обратно в объект, формируя её из числа
ТекущийОбъект.ДатаПериода = Дата(ГодЧислом, 1, 1);
КонецПроцедуры
Важный момент: если вы меняете число прямо на форме и хотите, чтобы другие элементы (например, динамические списки) реагировали мгновенно, добавьте обработчик события ПриИзменении для поля ГодЧислом, где принудительно обновляйте дату объекта.
Если заказчик настаивает на сохранении типа Дата и хочет «свободный ввод», мы можем использовать событие ОкончаниеВводаТекста. Это позволит пользователю написать «2024», а системе — автоматически превратить это в «01.01.2024».
Проанализируем, как реализовать такой перехват:
&НаКлиенте
Процедура ПериодГодОкончаниеВводаТекста(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, СтандартнаяОбработка)
// Пытаемся преобразовать введенный текст в число
Попытка
ВведенныйГод = Число(Текст);
Если ВведенныйГод > 1900 И ВведенныйГод < 2100 Тогда
Объект.ДатаПериода = Дата(ВведенныйГод, 1, 1);
СтандартнаяОбработка = Ложь; // Отменяем стандартную обработку 1С
КонецЕсли;
Исключение
// Если ввели не число, сработает стандартный механизм
КонецПопытки;
КонецПроцедуры
Посмотрим на сравнительную таблицу методов, чтобы выбрать оптимальный для вашего случая:
Разберем еще один нюанс, упомянутый на форуме: в некоторых типовых конфигурациях (например, ЗУП) работа с периодами реализована через «огород» из программных надстроек. Это связано с тем, что платформенные механизмы даты в 1С всегда включают в себя день и время, что иногда противоречит бизнес-логике «чистого года». Поэтому использование Числового реквизита на форме с последующей конвертацией в Дату в объекте остается «золотым стандартом» разработки под управляемые формы.
В завершение отметим, что выбор метода зависит от требований постановщика задачи. Если требуется строгое соответствие формату — используйте ФорматРедактирования. Если требуется удобство пользователя — используйте СписокВыбора или Число с кнопками регулирования.