При разработке документов в конфигурациях на базе 1С:Предприятие 8.3, особенно в таких решениях, как Зарплата и управление персоналом 3.1, часто возникает необходимость реализовать удобный выбор периода. Вместо стандартного поля ввода даты пользователю привычнее видеть текстовое представление, например, «Июль 2022». Однако в базе данных этот период должен храниться как полноценная дата (обычно первое число месяца). Рассмотрим подробно, как организовать двустороннюю связь между строковым реквизитом формы и реквизитом объекта типа Дата.
Представим ситуацию: у нас есть документ, в котором имеется реквизит ПериодНачисления (тип Дата). На форме документа мы создаем вспомогательный реквизит ПериодНачисленияСтрокой (тип Строка). Нам необходимо обеспечить:
Объект.ПериодНачисления.Проанализируем типовые механизмы. В конфигурации ЗУП 3.1 этот функционал уже реализован и вынесен в общие модули. Использование стандартных функций — это лучший способ избежать ошибок и обеспечить единство интерфейса.
Для того чтобы повторить механизм выбора периода как в типовых документах, выполним следующие шаги. Прежде всего, разберем работу с событиями формы.
В процедуре ПриСозданииНаСервере или ПриЧтенииНаСервере необходимо инициализировать строковый реквизит. Если мы просто выведем дату в строку, она будет выглядеть как «01.07.2022 0:00:00», что нам не подходит. Используем функцию получения представления месяца.
Рассмотрим пример кода для инициализации формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Если документ новый, можно установить текущий месяц
Если Объект.Ссылка.Пустая() Тогда
Объект.ПериодНачисления = НачалоМесяца(ТекущаяДата());
КонецЕсли;
// Преобразуем дату в красивую строку "Месяц Год"
ЗначениеПериодНачисления = Объект.ПериодНачисления;
Представление = ЗарплатаКадрыКлиентСервер.ПолучитьПредставлениеМесяца(ЗначениеПериодНачисления);
// Устанавливаем значение в реквизит формы
ПериодНачисленияСтрокой = Представление;
КонецПроцедуры
В этом коде мы используем метод ЗарплатаКадрыКлиентСервер.ПолучитьПредставлениеМесяца(), который корректно формирует строку на основании переданной даты. Это избавляет нас от ручного форматирования.
Теперь выясним, как передать данные обратно из строки в объект при изменении значения пользователем. Для поля ПериодНачисленияСтрокой на форме следует создать обработчик события ПриИзменении. В типовых конфигурациях за это отвечает клиентский модуль.
Проанализируем ситуацию, когда мы работаем с нестандартным документом. Нам нужно превратить строку обратно в дату. Самый надежный способ в рамках ЗУП — вызвать процедуру ЗарплатаКадрыКлиент.ПериодНачисленияПриИзменении, но если вы строите свою логику, можно воспользоваться следующим подходом:
&НаКлиенте
Процедура ПериодНачисленияСтрокойПриИзменении(Элемент)
// Вызываем типовой механизм для заполнения Объект.ПериодНачисления
// и обновления самой строки (например, если пользователь ввел "июл 22")
ПараметрыОбработки = Новый Структура;
ПараметрыОбработки.Вставить("ИмяРеквизитаДаты", "ПериодНачисления");
ПараметрыОбработки.Вставить("ИмяРеквизитаСтроки", "ПериодНачисленияСтрокой");
// Эта функция сама распарсит строку и запишет дату в Объект
ЗарплатаКадрыКлиент.ПериодНачисленияПриИзменении(ЭтаФорма, ПараметрыОбработки);
КонецПроцедуры
Важный момент: если вы используете собственные алгоритмы и не хотите зависеть от типовых модулей, вам придется реализовать «парсер» строки. Рассмотрим, как это сделать вручную.
Если ваша конфигурация не содержит модулей ЗарплатаКадрыКлиент, или вы работаете в пустой базе, можно применить алгоритм сопоставления. Разберем пример кода, который преобразует строку «Июль 2022» в дату 01.07.2022:
&НаКлиенте
Функция ПреобразоватьСтрокуВДату(Знач СтрПериод)
День = "01";
// Определяем номер месяца по вхождению подстроки
Если СтрНайти(СтрПериод, "Январь") > 0 Тогда
Месяц = "01";
ИначеЕсли СтрНайти(СтрПериод, "Февраль") > 0 Тогда
Месяц = "02";
ИначеЕсли СтрНайти(СтрПериод, "Март") > 0 Тогда
Месяц = "03";
ИначеЕсли СтрНайти(СтрПериод, "Апрель") > 0 Тогда
Месяц = "04";
ИначеЕсли СтрНайти(СтрПериод, "Май") > 0 Тогда
Месяц = "05";
ИначеЕсли СтрНайти(СтрПериод, "Июнь") > 0 Тогда
Месяц = "06";
ИначеЕсли СтрНайти(СтрПериод, "Июль") > 0 Тогда
Месяц = "07";
ИначеЕсли СтрНайти(СтрПериод, "Август") > 0 Тогда
Месяц = "08";
ИначеЕсли СтрНайти(СтрПериод, "Сентябрь") > 0 Тогда
Месяц = "09";
ИначеЕсли СтрНайти(СтрПериод, "Октябрь") > 0 Тогда
Месяц = "10";
ИначеЕсли СтрНайти(СтрПериод, "Ноябрь") > 0 Тогда
Месяц = "11";
Иначе
Месяц = "12";
КонецЕсли;
// Извлекаем последние 4 символа как год
Год = Прав(СокрЛП(СтрПериод), 4);
// Собираем строку формата "ДД.ММ.ГГГГ" и преобразуем в Дату
СтрокаДаты = День + "." + Месяц + "." + Год;
Попытка
Возврат Дата(СтрокаДаты);
Исключение
Возврат '00010101';
КонецПопытки;
КонецФункции
Этот метод прямолинеен, но эффективен. После получения даты её необходимо присвоить реквизиту Объект.ПериодНачисления.
Проанализируем типичную ошибку начинающих разработчиков: «При открытии существующего документа поле периода пустое». Это происходит из-за того, что данные реквизита ПериодНачисленияСтрокой существуют только «на экране» (в памяти формы) и не сохраняются в базе данных автоматически вместе с объектом.
Чтобы избежать этой проблемы, всегда используйте процедуру ПриЧтенииНаСервере на форме документа. В отличие от ПриСозданииНаСервере, она срабатывает каждый раз, когда данные объекта считываются из базы (например, после записи или при перечитывании данных).
Рассмотрим правильную структуру инициализации:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Важно использовать ТекущийОбъект или Объект.ПериодНачисления
Если ЗначениеЗаполнено(Объект.ПериодНачисления) Тогда
ПериодНачисленияСтрокой = Формат(Объект.ПериодНачисления, "ДФ='MMMM yyyy'");
КонецЕсли;
КонецПроцедуры
Использование форматной строки "ДФ='MMMM yyyy'" — это быстрый способ получить название месяца и год без использования внешних функций. Однако помните, что Формат() зависит от локализации системы (языковых настроек).
Для удобства пользователя можно включить у поля ПериодНачисленияСтрокой свойство «Кнопка регулирования». Это позволит переключать месяцы стрелками «вверх» и «вниз». Разберем, как это запрограммировать:
&НаКлиенте
Процедура ПериодНачисленияСтрокойРегулирование(Элемент, Направление, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Определяем шаг изменения (1 месяц или -1 месяц)
Шаг = ?(Направление > 0, 1, -1);
// Вычисляем новую дату
НоваяДата = ДобавитьМесяц(Объект.ПериодНачисления, Шаг);
Объект.ПериодНачисления = НоваяДата;
// Обновляем строковое представление
ПериодНачисленияСтрокой = ЗарплатаКадрыКлиентСервер.ПолучитьПредставлениеМесяца(НоваяДата);
КонецПроцедуры
Таким образом, мы создаем полноценный, удобный интерфейс, который полностью синхронизирован с данными документа. Мы рассмотрели три пути решения: использование богатого функционала ЗУП 3.1, ручной парсинг строк и применение форматных функций платформы. Выбор конкретного метода зависит от сложности вашей задачи и требований к конфигурации.