Почему при программном создании документа «Установка цен номенклатуры» на основании поступления табличная часть остается пустой?

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

Разберем частую задачу, с которой сталкиваются разработчики 1С: автоматическое формирование и проведение документа УстановкаЦенНоменклатуры при записи или проведении документа поступления товаров и услуг.

На первый взгляд, логика решения кажется простой: достаточно программно создать новый объект через СоздатьДокумент(), вызвать стандартный метод Заполнить() с передачей ссылки на документ-основание и записать его. Однако на практике созданный таким образом документ часто оказывается с пустой табличной частью. Проанализируем причины такого поведения платформы и рассмотрим способы правильной реализации этой задачи.

Анализ проблемы и стандартного заполнения

Рассмотрим код, который часто пытаются использовать в обработчиках событий (например, в процедуре ПослеЗаписи модуля документа):


НовыйДокум = Документы.УстановкаЦенНоменклатуры.СоздатьДокумент();
НовыйДокум.Дата = ТекущаяДата();    
НовыйДокум.Заполнить(Ссылка);

Попытка 
    НовыйДокум.Записать(РежимЗаписиДокумента.Проведение); 
Исключение 
    Сообщить("" + ОписаниеОшибки()); 
КонецПопытки;

Выясним причину, почему при интерактивном нажатии на кнопку «Ввести на основании» в интерфейсе пользователя документ заполняется корректно, а при выполнении этого же метода из кода табличная часть остается пустой:

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

Способы решения задачи

Рассмотрим подробнее два основных подхода к реализации автоматической установки цен.

Способ 1. Явное программное заполнение табличных частей

Если стандартная процедура Заполнить() не приносит желаемого результата, наиболее надежным решением является прямой перенос строк из табличной части документа поступления в новый документ установки цен.

Проанализируем пример явного заполнения номенклатуры и цен:


НовыйДокум = Документы.УстановкаЦенНоменклатуры.СоздатьДокумент();
НовыйДокум.Дата = ТекущаяДата();

// Заполняем табличную часть "Товары" вручную
Для Каждого СтрокаПоступления Из Ссылка.Товары Цикл
    НоваяСтрока = НовыйДокум.Товары.Добавить();
    НоваяСтрока.Номенклатура = СтрокаПоступления.Номенклатура;
    НоваяСтрока.Цена = СтрокаПоступления.Цена;
КонецЦикла;

// При необходимости заполняем табличную часть видов цен или реквизиты шапки
// ...

Попытка
    НовыйДокум.Записать(РежимЗаписиДокумента.Проведение);
Исключение
    ЗаписьЖурналаРегистрации("ОшибкаУстановкиЦен", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;

Способ 2. Использование подписок на события и фоновых заданий

Чтобы не снимать типовой документ с поддержки и избежать транзакционных блокировок при записи, рекомендуется придерживаться следующей архитектуры:

  1. Подписка на событие: Вместо редактирования модуля самого документа создадим подписку на событие ОбработкаПро проведения или ПриЗаписи для документа-источника.
  2. Отложенное проведение через фоновое задание: Из подписки запустим фоновое задание, которое создаст и проведет документ УстановкаЦенНоменклатуры вне транзакции основного документа. Это обеспечит стабильность работы при одновременной работе нескольких пользователей.
← На главную