В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача: при оформлении документа (например, поступления оборудования) автоматически создать объект в справочнике и зафиксировать его состав в регистре сведений. На первый взгляд кажется логичным поместить этот код в процедуру ОбработкаПроведения, однако это решение таит в себе множество архитектурных ловушек. Рассмотрим подробнее, как реализовать эту задачу правильно, избегая дублирования данных и избыточных блокировок базы данных.
Разберем ситуацию, описанную в теме. У нас есть документ «Поступление компьютеров» с табличной частью, где указаны комплектующие: системный блок, монитор, принтер и ИБП. Нам нужно создать элемент справочника Компьютеры и записать связку в регистр сведений СоставКомпьютера.
Проанализируем риски создания элемента справочника непосредственно в момент проведения документа:
Выясним причину, по которой опытные разработчики рекомендуют переносить создание справочника в форму документа или в событие ПередЗаписью.
Это наиболее прозрачный и безопасный способ для пользователя. Мы добавим в форму документа кнопку «Сформировать компьютер», которая выполнит всю работу на сервере и вернет готовую ссылку в реквизит документа.
Важный момент: начинающие разработчики часто сталкиваются с ошибкой Переменная не определена (Справочники). Это происходит при попытке обратиться к глобальному контексту Справочники на клиенте (в процедуре &НаКлиенте). Помните, что работа с базой данных возможна только на сервере.
Рассмотрим пример кода для реализации этой логики:
&НаКлиенте
Процедура КомандаСформироватьКомпьютер(Команда)
// Передаем данные текущей строки на сервер
ТекущиеДанные = Элементы.СоставОборудования.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Вызываем серверную функцию для поиска или создания
СсылкаНаКомпьютер = СоздатьИлиНайтиКомпьютерНаСервере(ТекущиеДанные.НаименованиеКомпьютера);
// Заполняем реквизит в документе
ТекущиеДанные.КомпьютерСсылка = СсылкаНаКомпьютер;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СоздатьИлиНайтиКомпьютерНаСервере(ИмяКомпьютера)
// Сначала ищем по наименованию, чтобы не плодить дубли
НайденнаяСсылка = Справочники.Компьютеры.НайтиПоНаименованию(ИмяКомпьютера);
Если Не НайденнаяСсылка.Пустая() Тогда
Возврат НайденнаяСсылка;
КонецЕсли;
// Если не нашли — создаем новый
НовыйОбъект = Справочники.Компьютеры.СоздатьЭлемент();
НовыйОбъект.Наименование = ИмяКомпьютера;
НовыйОбъект.Записать();
Возврат НовыйОбъект.Ссылка;
КонецФункции
Чтобы эффективно хранить информацию о том, из каких частей состоит компьютер, проанализируем структуру регистра сведений. Оптимально использовать периодический регистр сведений. Это позволит не просто хранить текущий состав, но и видеть историю изменений (например, когда монитор был заменен на другой).
Рекомендуемая структура регистра:
Компьютер (тип СправочникСсылка.Компьютеры).СистемныйБлок, Монитор, Принтер, ИБП (типы СправочникСсылка.Номенклатура).Запись в этот регистр должна происходить в процедуре ОбработкаПроведения документа. Поскольку на этот момент ссылка на компьютер уже создана и записана в документ (одним из способов выше), мы просто фиксируем состояние в базе данных.
Разберем пример кода в модуле объекта документа:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Очищаем старые записи по этому документу, если регистр подчинен регистратору
Движения.СоставКомпьютера.Записывать = Истина;
Движения.СоставКомпьютера.Очистить();
Для Каждого ТекСтрока Из ТабличнаяЧасть Цикл
// Проверяем, заполнен ли созданный ранее компьютер
Если ТекСтрока.КомпьютерСсылка.Пустая() Тогда
Сообщить("Не заполнен объект Компьютер в строке " + ТекСтрока.НомерСтроки);
Отказ = Истина;
Продолжить;
КонецЕсли;
// Создаем запись в регистре
Движение = Движения.СоставКомпьютера.Добавить();
Движение.Период = Дата;
Движение.Компьютер = ТекСтрока.КомпьютерСсылка;
Движение.СистемныйБлок = ТекСтрока.СистемныйБлок;
Движение.Монитор = ТекСтрока.Монитор;
Движение.Принтер = ТекСтрока.Принтер;
Движение.ИБП = ТекСтрока.ИБП;
КонецЦикла;
КонецПроцедуры
Если мы решили отказаться от справочника Компьютеры и хранить только текстовое название, мы можем использовать его как измерение регистра сведений с типом Строка. Однако это лишит нас возможности ссылаться на этот компьютер в других документах (например, в «Акте ремонта» или «Списании»).
Рассмотрим рекомендации по идентификации объектов:
Проанализируем ситуацию: использование функции НайтиПоНаименованию эффективно только в случае строгой дисциплины ввода данных. Если пользователь назовет компьютер один раз «Комп-1», а другой раз «Комп 1» (с пробелом), система создаст два разных элемента. Для автоматизированных систем лучше использовать скрытые технические реквизиты поиска.
Подводя итог, придерживайтесь следующего алгоритма действий при разработке подобных механизмов в 1С:
НовыйОбъект.Записать(). Поиск по коду или уникальному идентификатору надежнее, чем по наименованию.&НаКлиенте мы только взаимодействуем с пользователем, а &НаСервере — работаем с базой данных и объектами метаданных.Такой подход обеспечит стабильную работу системы, отсутствие дублей и корректное отображение состава оборудования в отчетах на любую дату.