При разработке и доработке конфигураций на платформе 1С (особенно в типовых решениях, таких как "Бухгалтерия предприятия") часто возникает необходимость расширить состав данных документа без изменения самой конфигурации. Для этого используется механизм дополнительных реквизитов и сведений. Давайте подробно разберем, как программно создавать и заполнять дополнительные сведения, проанализируем частые ошибки новичков и рассмотрим лучшие практики разработки.
Часто начинающие программисты пытаются добавить дополнительное сведение напрямую в набор записей регистра, допуская ошибку в типизации данных. Посмотрим на пример некорректного кода:
&НаСервере
Процедура СоздатьДопСведенияНаСервере()
Набор = РегистрыСведений.ДополнительныеСведения.СоздатьНаборЗаписей();
НоваяСтрокаНабора = Набор.Добавить();
НоваяСтрокаНабора.Объект = Документы.АктСверкиВзаиморасчетов; // ОШИБКА ЗДЕСЬ
НоваяСтрокаНабора.Свойство = "Свойство";
НоваяСтрокаНабора.Значение = "лалала";
Набор.Записать();
КонецПроцедуры
Этот код вызовет ошибку: Запись не верна! Значение поля "Объект" не может быть пустым!. Выясним причину. В коде в поле Объект передается Документы.АктСверкиВзаиморасчетов, что является объектом типа Менеджер документа. Однако измерение Объект в регистре сведений ДополнительныеСведения имеет тип Ссылка на документ. Нам необходимо передавать ссылку на конкретный экземпляр документа, для которого формируются эти допсведения, а не весь класс документов.
Кроме того, в поле Свойство передается обычная строка, в то время как там должна быть ссылка на элемент Плана видов характеристик (ПВХ).
Прежде чем писать правильный код, проанализируем, как устроен этот механизм в 1С. Важно понимать разницу между терминами:
ДополнительныеСведения. Они открываются по отдельной кнопке (значок с папкой и листом) на форме. Их главное преимущество: для добавления отметки пользователю не нужно перепроводить документ (достаточно прав на изменение самих доп. сведений).Чтобы сведение появилось в системе, нам нужно взаимодействовать с тремя объектами:
ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения — здесь хранится само определение свойства (его тип, имя и т.д.).Справочники.НаборыДополнительныхРеквизитовИСведений — здесь свойство привязывается к конкретному типу документа (например, к Заказ-наряду или Акту сверки).РегистрыСведений.ДополнительныеСведения — здесь хранятся конкретные значения свойства для конкретных документов.Рассмотрим по шагам, как программно создать новое дополнительное сведение, если его еще нет в базе. В примере ниже мы создаем сведение для документа ЗаказНаряд.
Процедура ДобавлениеДополнительныхСведений()
ИмяРеквизита = "TOS_Test";
// Включим константу использования, если она выключена
Если Не Константы.ИспользоватьДополнительныеРеквизитыИСведения.Получить() Тогда
Константы.ИспользоватьДополнительныеРеквизитыИСведения.Установить(Истина);
КонецЕсли;
// Попробуем найти реквизит по наименованию
ДопРеквизитСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию(ИмяРеквизита);
Если НЕ ЗначениеЗаполнено(ДопРеквизитСсылка) Тогда
// Создаем новый элемент ПВХ
ДопРеквизитОбъект = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.СоздатьЭлемент();
ДопРеквизитОбъект.Наименование = ИмяРеквизита;
ДопРеквизитОбъект.ТипЗначения = Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(250));
ДопРеквизитОбъект.Виден = Истина;
ДопРеквизитОбъект.Доступен = Истина;
ДопРеквизитОбъект.Заголовок = ИмяРеквизита;
ДопРеквизитОбъект.Имя = СтрЗаменить(ИмяРеквизита," ","");
ДопРеквизитОбъект.НаборСвойств = Справочники.НаборыДополнительныхРеквизитовИСведений.Документ_ЗаказНаряд;
ДопРеквизитОбъект.ЭтоДополнительноеСведение = Истина;
ДопРеквизитОбъект.ВидСвойств = Перечисления.ВидыСвойств.ДополнительныеСведения;
ДопРеквизитОбъект.Записать();
ДопРеквизитСсылка = ДопРеквизитОбъект.Ссылка;
КонецЕсли;
// Добавим наше сведение в набор дополнительных реквизитов документа
НаборДополнительныхРеквизитов = Справочники.НаборыДополнительныхРеквизитовИСведений.Документ_ЗаказНаряд.ПолучитьОбъект();
Если НаборДополнительныхРеквизитов.ДополнительныеСведения.Найти(ДопРеквизитСсылка, "Свойство") = Неопределено Тогда
Стр = НаборДополнительныхРеквизитов.ДополнительныеСведения.Добавить();
Стр.Свойство = ДопРеквизитСсылка;
НаборДополнительныхРеквизитов.Записать();
КонецЕсли;
КонецПроцедуры
Если дополнительное сведение уже создано в пользовательском режиме (или кодом выше), и нам нужно программно заполнить его для конкретного документа, можно использовать менеджер записи. Посмотрим на рабочий пример для заполнения печатного номера:
// Получаем нужный номер для печати
нм = ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(ЭтотОбъект.Номер, Истина, Истина);
// Находим нужное свойство в ПВХ
ДополнительныеСведения = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("№ счета 1С (Печатный)", Истина);
// Записываем значение в независимый регистр
МенеджерЗаписи = РегистрыСведений.ДополнительныеСведения.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = ЭтотОбъект.Ссылка; // Передаем корректную ссылку на документ!
МенеджерЗаписи.Свойство = ДополнительныеСведения;
МенеджерЗаписи.Значение = нм;
МенеджерЗаписи.Записать(Истина);
Хотя пример с менеджером записи работает, в современных конфигурациях на базе БСП (например, в Бухгалтерии 3.0) не рекомендуется писать данные напрямую в регистр. Для этих целей существует готовый программный интерфейс (API).
Рассмотрим подробнее правильный метод записи через БСП. Для записи значений используется общий модуль УправлениеСвойствами. Этот метод автоматически обрабатывает все проверки, блокировки и транзакции.
ТаблицаСвойств = Новый ТаблицаЗначений;
ТаблицаСвойств.Колонки.Добавить("Свойство");
ТаблицаСвойств.Колонки.Добавить("Значение");
НоваяСтрока = ТаблицаСвойств.Добавить();
НоваяСтрока.Свойство = СсылкаНаНашеСвойство;
НоваяСтрока.Значение = "Наше значение";
// Вызов стандартного метода БСП
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(СсылкаНаДокумент, ТаблицаСвойств);
Важные замечания:
Строка. Гораздо правильнее при создании ПВХ указать тип Булево. Это позволит легко делать отборы в динамических списках и отчетах. В коде это выглядит так: ДопРеквизитОбъект.ТипЗначения = Новый ОписаниеТипов("Булево");.ОповеститьОбИзменении(СсылкаНаДокумент);.Неопределено. Если по логике задачи у всех прошлых документов должно стоять значение по умолчанию (например, Ложь для "Есть ошибка"), потребуется написать разовую обработку для пакетной записи значений во все нужные документы через цикл.