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