Почему при программном создании расходной накладной в 1С:УНФ записывается нулевая сумма и как это исправить?

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

В процессе программной разработки в среде 1С:Предприятие 8 (особенно в конфигурациях, построенных на современных ERP-платформах, таких как 1С:Управление нашей фирмой (УНФ) 1.6 / 3.0, 1С:Управление торговлей 11 или 1С:Комплексная автоматизация) разработчики часто сталкиваются с неочевидным поведением системы. Один из таких классических багов — когда созданный программно документ РасходнаяНакладная записывается или проводится с нулевой суммой в шапке документа, при этом в табличной части Запасы все колонки (количество, цена, сумма, всего) заполнены абсолютно корректно.

Особенно сильно сбивает с толку то, что ошибка может возникать периодически — например, примерно на каждом десятом документе, в то время как остальные девять проводятся без каких-либо замечаний. В этой статье мы подробно разберем, почему возникает эта проблема, как на нее влияют механизмы расчета скидок и как правильно писать код программного создания документов, чтобы избежать подобных ошибок.

В чем кроется причина проблемы?

Главная причина «плавающего» характера этой ошибки — использование универсальной функции ЗаполнитьЗначенияСвойств(Получатель, Источник) при копировании или заполнении нового документа на основании существующего. Этот метод очень удобен, так как позволяет в одну строчку кода перенести десятки реквизитов. Однако при «слепом» копировании переносятся не только очевидные реквизиты (такие как контрагент, договор, организация или склад), но и служебные реквизиты шапки документа, отвечающие за расчет цен, налогов и скидок.

Проанализируем, какие именно реквизиты ломают логику расчета суммы в современных конфигурациях 1С:

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

Именно поэтому ошибка возникает «каждый десятый раз»: она проявляется только тогда, когда в качестве документа-источника выступает документ, в котором реально были рассчитаны или применены скидки. Если исходный документ был без скидок, флаг СкидкиРассчитаны равен Ложь, и программное создание проходит успешно.

Решение проблемы: Правильные подходы к программному созданию документов

Рассмотрим несколько надежных способов программного создания и заполнения документов в 1С, которые исключают появление подобных багов.

Способ 1. Использование списка исключений при копировании свойств

Если вы продолжаете использовать функцию ЗаполнитьЗначенияСвойств(), всегда явно указывайте третий параметр — СписокИсключений. В него необходимо передать строку с именами всех служебных реквизитов, сумм, флагов скидок и уникальных идентификаторов, которые не должны копироваться «вслепую».

Разберем пример правильного копирования реквизитов шапки:


// Создаем новый объект документа
НовыйДокумент = Документы.РасходнаяНакладная.СоздатьДокумент();

// Задаем список реквизитов, которые нельзя копировать напрямую
СписокИсключений = "Номер, Дата, СуммаДокумента, СкидкиРассчитаны, ВариантСкидки, ПроцентОптовойСкидки";

// Копируем только безопасные реквизиты
ЗаполнитьЗначенияСвойств(НовыйДокумент, ДокументИсточник, , СписокИсключений);

// Устанавливаем текущую дату
НовыйДокумент.Дата = ТекущаяДата();

Использование списка исключений гарантирует, что система не перенесет старый флаг рассчитанных скидок, и при записи документа сумма будет рассчитана заново на основании фактически заполненных строк табличной части.

Способ 2. Пополевое заполнение реквизитов

Наиболее надежный, хотя и более трудоемкий метод — это явное заполнение каждого необходимого реквизита в коде. Этот подход полностью исключает перенос скрытого «мусора» из других документов.

Рассмотрим пример пополевого заполнения шапки и табличной части:


НовыйДокумент = Документы.РасходнаяНакладная.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Организация = ДокументИсточник.Организация;
НовыйДокумент.Контрагент = ДокументИсточник.Контрагент;
НовыйДокумент.Договор = ДокументИсточник.Договор;
НовыйДокумент.Склад = ДокументИсточник.Склад;

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

Способ 3. Вызов штатных процедур пересчета документа

В современных конфигурациях 1С крайне не рекомендуется рассчитывать итоги вручную простым сложением сумм строк в коде. В модуле объекта каждого сложного документа, как правило, присутствуют экспортные процедуры для расчета всех зависимых реквизитов. В УНФ для этого используется метод объекта РассчитатьСуммуДокумента().

Проанализируем правильную последовательность вызовов при записи документа:


// После того как ТЧ "Запасы" заполнена программно:

// 1. Сбрасываем флаг рассчитанных скидок, чтобы заставить систему пересчитать их
НовыйДокумент.СкидкиРассчитаны = Ложь;

// 2. Вызываем стандартный метод объекта для расчета итогов шапки
НовыйДокумент.РассчитатьСуммуДокумента();

// 3. Записываем и проводим документ
НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);

Метод РассчитатьСуммуДокумента() гарантирует, что реквизит СуммаДокумента в шапке будет равен математической сумме колонок табличной части с учетом всех налогов, скидок и наценок. Данный вызов заменяет ручной расчет и защищает код от изменений в логике проведения при обновлениях конфигурации.

Способ 4. Инициализация документа через встроенные механизмы (Заполнить)

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

Пример использования метода:


НовыйДокумент = Документы.РасходнаяНакладная.СоздатьДокумент();
// Запускается стандартный обработчик "ОбработкаЗаполнения"
НовыйДокумент.Заполнить(ДокументОснование); 

// После автоматического заполнения можно скорректировать нужные поля
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Записать(РежимЗаписиДокумента.Проведение);

Этот способ является наиболее приоритетным с точки зрения стандартов разработки фирмы «1С», так как он задействует встроенное API конфигурации и автоматически заполняет все служебные регистры и реквизиты в строгом соответствии с методологией учета программы.

← На главную