Как в 1С вывести оставшееся количество дней до определенной даты на форму элемента и списка

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке учетных механизмов в 1С часто возникает задача отслеживания сроков: срока действия визы, окончания договора, поверки оборудования или приближающегося дня рождения. Начинающие разработчики нередко пытаются сохранить количество оставшихся дней непосредственно в реквизит объекта справочника или документа при его записи. Однако на следующий день сохраненное число становится неактуальным, так как текущая дата изменилась, а объект в базе данных остался прежним.

Проанализируем, почему динамически изменяемые значения нельзя хранить в реквизитах базы данных, и подробно разберем правильные способы расчета и отображения таких показателей на управляемой форме элемента и в форме списка.

Архитектурный принцип: почему динамические данные не хранят в реквизитах объекта

Если записать в реквизит справочника результат выражения разницы дат, значение останется статичным до тех пор, пока пользователь вручную не откроет и не перепишет этот элемент. Хранение таких данных в базе потребовало бы ежедневной регламентной перезаписи всех элементов справочника, что создает неоправданную нагрузку на базу данных и искажает историю изменений объектов.

В платформе 1С действует фундаментальное правило: динамически изменяемые значения, зависящие от текущей даты или времени, должны вычисляться "на лету" при открытии формы или при формировании динамического списка.

Способ 1. Отображение вычисленного значения на форме элемента через реквизит формы

Рассмотрим типовую ошибку при попытке записать значение напрямую в элементы формы на клиенте. Если написать код вида Элементы.ОсталосьДней = ..., платформа выдаст исключение Поле объекта недоступно для записи, поскольку коллекция Элементы предназначена исключительно для управления визуальными элементами управления, а не для хранения данных.

Разберем по шагам правильный алгоритм вывода данных через реквизит формы:

  1. Откроем форму элемента справочника в конфигураторе.
  2. На вкладке «Реквизиты» добавим новый реквизит формы (не путать с реквизитом объекта), назовем его ОсталосьДней с типом Число.
  3. Перетащим созданный реквизит в дерево элементов формы. В свойствах созданного поля установим вид Поле надписи либо Поле ввода с включенным свойством ТолькоПросмотр = Истина.
  4. Заполним значение реквизита в серверных обработчиках формы.

Посмотрим на пример правильной реализации в модуле формы элемента:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    РассчитатьОстатокДней();
КонецПроцедуры

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    РассчитатьОстатокДней();
КонецПроцедуры

&НаСервере
Процедура РассчитатьОстатокДней()
    Если ЗначениеЗаполнено(Объект.ДатаСледующегоВыезда) Тогда
        // Используем ТекущаяДатаСеанса для учета часового пояса пользователя
        ТекущаяДата = НачалоДня(ТекущаяДатаСеанса());
        ДатаВыезда = НачалоДня(Объект.ДатаСледующегоВыезда);
        ОсталосьДней = (ДатаВыезда - ТекущаяДата) / 86400;
    Иначе
        ОсталосьДней = 0;
    КонецЕсли;
КонецПроцедуры

Обратите внимание на использование функции ТекущаяДатаСеанса() вместо ТекущаяДата(). Это гарантирует корректный расчет с учетом локального времени пользователя, если сервер 1С находится в другом часовом поясе.

Способ 2. Вывод через декорацию надписи

Если не требуется создавать отдельный реквизит формы, можно воспользоваться элементом формы вида Декорация - Надпись. Разберем этот вариант:

  1. Добавим в элементы формы декорацию с именем ДекорацияОсталосьДней.
  2. В обработчике открытия или чтения формы установим свойство Заголовок для этой декорации.

Посмотрим на пример кода:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    Если ЗначениеЗаполнено(Объект.ДатаСледующегоВыезда) Тогда
        ДнейДоСобытия = (НачалоДня(Объект.ДатаСледующегоВыезда) - НачалоДня(ТекущаяДатаСеанса())) / 86400;
        Элементы.ДекорацияОсталосьДней.Заголовок = "Осталось дней: " + Формат(ДнейДоСобытия, "ЧГ=0");
    Иначе
        Элементы.ДекорацияОсталосьДней.Заголовок = "Дата выезда не указана";
    КонецЕсли;
КонецПроцедуры

Способ 3. Вычисление и отображение в форме списка (Динамический список)

Когда требуется видеть оставшееся количество дней сразу по всем сотрудникам в таблице справочника, расчет на форме элемента не подходит. Для этого используют возможности запроса в динамическом списке формы списка.

Разберем по шагам настройку динамического списка:

  1. Откроем форму списка справочника и выделим основной реквизит Список.
  2. В палитре свойств включим флаг ПроизвольныйЗапрос и перейдем к редактированию текста запроса.
  3. Добавим вычисляемое поле с помощью функции языка запросов РАЗНОСТЬДАТ:

ВЫБРАТЬ
    СправочникВизы.Ссылка КАК Ссылка,
    СправочникВизы.ПометкаУдаления КАК ПометкаУдаления,
    СправочникВизы.Наименование КАК Наименование,
    СправочникВизы.ДатаСледующегоВыезда КАК ДатаСледующегоВыезда,
    РАЗНОСТЬДАТ(&ТекущаяДата, СправочникВизы.ДатаСледующегоВыезда, ДЕНЬ) КАК ДнейДоВыезда
ИЗ
    Справочник.Визы КАК СправочникВизы

Поскольку в языке запросов 1С отсутствует функция получения текущей системной даты, ее необходимо передавать в виде параметра из модуля формы списка.

В модуле формы списка напишем процедуру установки параметра:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Список.Параметры.УстановитьЗначениеПараметра("ТекущаяДата", НачалоДня(ТекущаяДатаСеанса()));
КонецПроцедуры

После добавления поля ДнейДоВыезда в таблицу динамического списка пользователи смогут не только видеть актуальный остаток дней, но и выполнять по этой колонке сортировку, группировку и отбор стандартными средствами платформы.

Настройка цветового выделения (Условное оформление)

Для визуального контроля приближающихся сроков настроим подсветку строк в динамическом списке с помощью механизма УсловноеОформление. Например, выделим красным цветом записи, где срок выезда уже наступил или наступает в течение ближайших трех дней.

Посмотрим на пример программной настройки условного оформления в процедуре ПриСозданииНаСервере:


&НаСервере
Процедура НастроитьОформлениеСроков()
    ЭлементОформления = УсловноеОформление.Элементы.Добавить();
    
    // Определяем оформление: красный цвет текста
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Красный);
    ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Шрифт", Новый Шрифт(,, Истина)); // Полужирный
    
    // Задаем условие: ДнейДоВыезда <= 3
    ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Список.ДнейДоВыезда");
    ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.МеньшеИлиРавно;
    ЭлементУсловия.ПравоеЗначение = 3;
    
    // Указываем оформляемые поля
    ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
    ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ДнейДоВыезда");
КонецПроцедуры

Регламентные задачи и фоновый контроль сроков

Если рассчитанные дни требуются не только для визуального отображения пользователю, но и для автоматической отправки уведомлений на почту или формирования служебных заданий, создают Регламентное задание. Такое задание выполняется на сервере по расписанию (например, ежедневно в полночь), выбирает запросом объекты с критическим сроком и выполняет необходимые фоновые действия без участия пользователя.

← На главную