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