Как в 1С сохранить расписание регламентного задания в справочнике и использовать его в дальнейшем?

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

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

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

Способ 1: Хранение расписания в виде XML-строки

Это универсальный и надежный метод, который подходит для многих объектов 1С. Суть его в том, чтобы преобразовать объект расписания в XML-строку для сохранения и выполнить обратное преобразование при чтении. Для этого используются функции ЗначениеВСтрокуXML и ЗначениеИзСтрокиXML.

Рассмотрим по шагам, как это реализовать в форме элемента справочника.

  1. Создайте в справочнике реквизит для хранения расписания, например, РасписаниеСтрока с типом Строка неограниченной длины. Это важно, так как XML-представление может быть довольно длинным.
  2. В форме элемента справочника разместите код для вызова диалога настройки расписания.

Посмотрим на пример кода. Команда НастроитьРасписание вызывает процедуру, которая открывает стандартный диалог.


&НаКлиенте
Процедура НастроитьРасписание(Команда)
    
    // Переменная для хранения объекта расписания
    Перем пРасписание;

    // Если реквизит с расписанием еще не заполнен, создаем новый пустой объект
    Если ПустаяСтрока(Объект.РасписаниеСтрока) Тогда
        пРасписание = Новый РасписаниеРегламентногоЗадания();
    // Если расписание уже было сохранено, восстанавливаем объект из XML-строки
	Иначе
		пРасписание = ЗначениеИзСтрокиXML(Объект.РасписаниеСтрока);
    КонецЕсли;

    // Создаем и показываем диалог настройки, передавая в него текущее расписание
    Диалог = Новый ДиалогРасписанияРегламентногоЗадания(пРасписание);
    Диалог.Показать(Новый ОписаниеОповещения("ОткрытьРасписаниеЗавершение", ЭтотОбъект));
    
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьРасписаниеЗавершение(НовоеРасписание, Контекст) Экспорт
    
    // Если пользователь нажал "Отмена" в диалоге, ничего не делаем
    Если НовоеРасписание = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Преобразуем (сериализуем) полученный из диалога объект расписания в XML-строку
    // и записываем в реквизит объекта
    Объект.РасписаниеСтрока = ЗначениеВСтрокуXML(НовоеРасписание);

КонецПроцедуры             

// Эти функции лучше вынести в общий модуль с флагами "Сервер" и "Вызов сервера"

&НаСервереБезКонтекста
Функция ЗначениеВСтрокуXML(Значение) Экспорт
	
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку();
	СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Значение);
	Возврат ЗаписьXML.Закрыть();

КонецФункции

&НаСервереБезКонтекста
Функция ЗначениеИзСтрокиXML(СтрокаXML) Экспорт
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(СтрокаXML);
	Значение = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);
	Возврат Значение;
	
КонецФункции

Важный момент: Если при выполнении кода возникает ошибка Ошибка разбора XML... AttValue: ' expected, это почти всегда означает, что XML-строка, которую вы пытаетесь прочитать, повреждена или обрезана. Убедитесь, что реквизит, в котором вы храните строку (в нашем примере Объект.РасписаниеСтрока), имеет тип Строка неограниченной длины.

Способ 2: Использование встроенных методов ВСтроку() и ИзСтроки()

Для объекта РасписаниеРегламентногоЗадания платформа предоставляет специализированные методы для преобразования в строку и обратно. Этот способ проще, так как не требует написания дополнительных функций сериализации. Если же вам требуется сформировать строку в особом формате для внешних систем, можно использовать конструктор Cron расписания.

Код будет выглядеть немного иначе.


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

    Диалог = Новый ДиалогРасписанияРегламентногоЗадания(пРасписание);
    Диалог.Показать(Новый ОписаниеОповещения("ОткрытьРасписаниеЗавершение", ЭтотОбъект));
    
КонецПроцедуры

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

КонецПроцедуры

Этот подход более лаконичен и предназначен специально для работы с расписаниями. Строка, генерируемая методом ВСтроку(), также является довольно длинной, поэтому требование к реквизиту (строка неограниченной длины) сохраняется.

Способ 3: Самый надежный метод — ХранилищеЗначения

Чтобы полностью избежать проблем с преобразованием в строку, обрезанием и ошибками парсинга, можно использовать реквизит с типом ХранилищеЗначения. Этот тип данных предназначен для хранения любых сериализуемых объектов 1С. Платформа сама позаботится о корректном сохранении и восстановлении объекта.

  1. Создайте в справочнике реквизит, например, РасписаниеХранилище с типом ХранилищеЗначения.
  2. Измените код для работы с этим типом.

&НаКлиенте
Процедура НастроитьРасписание(Команда)
    // Получаем расписание с сервера
    ПолучитьРасписаниеССервера();
КонецПроцедуры

&НаСервере
Процедура ПолучитьРасписаниеССервера()
    // Получаем объект из хранилища. Если хранилище пустое, .Получить() вернет Неопределено
    пРасписание = Объект.РасписаниеХранилище.Получить();

    // Если расписания еще нет, создаем новое
    Если пРасписание = Неопределено Тогда
        пРасписание = Новый РасписаниеРегламентногоЗадания();
    КонецЕсли;

    // Открываем диалог на клиенте после получения данных
    ОткрытьДиалогНаКлиенте(пРасписание);
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьДиалогНаКлиенте(пРасписание)
    Диалог = Новый ДиалогРасписанияРегламентногоЗадания(пРасписание);
    Диалог.Показать(Новый ОписаниеОповещения("ОткрытьРасписаниеЗавершение", ЭтотОбъект));
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьРасписаниеЗавершение(НовоеРасписание, Контекст) Экспорт
    
    Если НовоеРасписание = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Вызываем серверную процедуру для сохранения объекта в хранилище
    СохранитьРасписаниеНаСервере(НовоеРасписание);
КонецПроцедуры

&НаСервере
Процедура СохранитьРасписаниеНаСервере(НовоеРасписание)
    // Помещаем объект в хранилище. Платформа сама выполнит сериализацию.
    Объект.РасписаниеХранилище = Новый ХранилищеЗначения(НовоеРасписание);
КонецПроцедуры

Использование ХранилищеЗначения является предпочтительным методом, так как он наиболее надежен и избавляет от ручного управления преобразованиями.

Как использовать сохраненное расписание для создания документов?

После того как расписание сохранено, его можно использовать в регламентном задании или обработке. Алгоритм действий следующий:

  1. Получить объект расписания. В вашей обработке вы читаете реквизит (строку или хранилище) и восстанавливаете из него полноценный объект РасписаниеРегламентногоЗадания одним из способов, описанных выше.
  2. Проанализировать расписание. У объекта расписания нет метода "ПолучитьДатыВыполненияЗаПериод". Поэтому для определения, нужно ли создавать документ в конкретный день, необходимо перебрать даты в интересующем вас периоде и для каждой даты проверить, соответствует ли она настройкам расписания. Для этого анализируются свойства объекта: ДниНедели, ДниМесяца, Месяцы и т.д.
  3. Создать документ. Если проверка показала, что на текущую дату запланировано выполнение, вы создаете необходимый документ.

Этот алгоритм обычно реализуется в регламентном задании, которое запускается, например, раз в день, и проверяет все объекты, для которых нужно создать документы по их индивидуальным расписаниям. При реализации таких механизмов «с нуля» полезно изучить фоновые задания, отслеживание результата и индикацию прогресса без БСП.

← На главную