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