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

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

В процессе разработки и автоматизации на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда при программном изменении реквизита документа код выполняется без ошибок, отладчик показывает успешное присвоение значения, но после вызова метода Записать() изменения в базе данных не сохраняются. Особенно часто эта проблема проявляется в типовых конфигурациях, таких как 1С:Бухгалтерия предприятия, при работе с банковскими и кассовыми документами.

В этой статье мы подробно разберем, почему возникает подобная ошибка на примере документа ПоступлениеНаРасчетныйСчет, проанализируем внутреннюю архитектуру хранения данных в типовых конфигурациях и рассмотрим правильные методы программного заполнения реквизитов.

Анализ исходной проблемы

Рассмотрим типовой сценарий, с которым столкнулся автор темы. Нам необходимо программно найти документ по входящему номеру и заполнить в нем сумму банковских услуг (комиссии). Исходный код выглядит следующим образом:


СсылкаНаДокумент = Документы.ПоступлениеНаРасчетныйСчет.НайтиПоРеквизиту("НомерВходящегоДокумента", Выборка.НомерВходящегоДокумента);
ТекущийДокумент = СсылкаНаДокумент.ПолучитьОбъект();
ТекущийДокумент.СуммаУслуг = Сумма_Услуг;
ТекущийДокумент.Записать(РежимЗаписи.Запись);

При пошаговой отладке данного фрагмента кода переменная Сумма_Услуг содержит корректное числовое значение, и свойство ТекущийДокумент.СуммаУслуг успешно принимает это значение. Однако после завершения транзакции записи и открытия документа в пользовательском интерфейсе поле «Сумма услуг» остается пустым или возвращается к своему прежнему значению. Выясним причину такого поведения платформы.

Причина 1. Виртуальные реквизиты формы и перезапись данных

Первая и самая главная причина кроется в различиях между реквизитами формы и реквизитами объекта (метаданными). В типовой конфигурации «1С:Бухгалтерия предприятия» поле «Сумма услуг» отображается на форме документа для удобства пользователя. Визуально оно может находиться в шапке или подвале документа, создавая иллюзию того, что это простой реквизит шапки.

На самом деле, на уровне метаданных документа ПоступлениеНаРасчетныйСчет отдельного реквизита СуммаУслуг в шапке может не существовать вовсе, либо он является расчетным. Физически эти данные хранятся в строках табличной части РасшифровкаПлатежа.

При интерактивной работе пользователя на форме срабатывают обработчики событий, которые переносят данные из полей ввода в соответствующие строки табличной части. При программном же обращении к объекту события формы не вызываются, и прямое присвоение значения несуществующему или пересчитываемому реквизиту объекта просто игнорируется или сбрасывается.

Причина 2. Работа обработчиков «ПередЗаписью» и подписок на события

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

  1. Платформа инициирует запись объекта и вызывает предопределенную процедуру ПередЗаписью в модуле документа.
  2. Внутри этого обработчика вызываются стандартные процедуры расчета (например, пересчет суммы НДС, общей суммы документа и суммы услуг на основании данных табличных частей).
  3. Программа видит, что табличная часть РасшифровкаПлатежа пуста или содержит строки, в которых колонка СуммаУслуг равна нулю.
  4. Алгоритм пересчета принудительно перезаписывает значение реквизита шапки СуммаУслуг нулевым значением, затирая то, что было присвоено программно перед вызовом метода Записать().
  5. Также могут отрабатывать Подписки на события (найти их можно в ветке конфигурации «Общие» — «Подписки на события»), выполняющие аналогичные функции контроля и перезаписи данных для группы схожих документов.

Как правильно решить проблему программно?

Чтобы успешно записать сумму услуг, нам необходимо работать напрямую с источником данных — табличной частью РасшифровкаПлатежа. Рассмотрим два практических сценария реализации этой задачи.

Сценарий А. Изменение суммы услуг в существующем документе

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


СсылкаНаДокумент = Документы.ПоступлениеНаРасчетныйСчет.НайтиПоРеквизиту("НомерВходящегоДокумента", Выборка.НомерВходящегоДокумента);

Если ЗначениеЗаполнено(СсылкаНаДокумент) Тогда
    ТекущийДокумент = СсылкаНаДокумент.ПолучитьОбъект();
    
    // Проверяем, заполнена ли табличная часть расшифровки платежа
    Если ТекущийДокумент.РасшифровкаПлатежа.Количество() > 0 Тогда
        // Записываем значение в первую строку табличной части
        СтрокаРасшифровки = ТекущийДокумент.РасшифровкаПлатежа[0];
        СтрокаРасшифровки.СуммаУслуг = Сумма_Услуг;
        
        // ВАЖНО: При заполнении суммы услуг необходимо также заполнить 
        // связанные реквизиты для корректного отражения расходов в бухгалтерском учете
        СтрокаРасшифровки.СчетЗатрат = ПланыСчетов.Хозрасчетный.ПрочиеРасходы; // Счет 91.02
        
        // Заполняем субконто для счета затрат (статью прочих расходов)
        СтрокаРасшифровки.СубконтоСтрока = Справочники.ПрочиеДоходыИРасходы.РасходыНаУслугиБанков;
        
        // Записываем документ с проведением, если он уже был проведен ранее
        РежимЗаписиДокумента = ?(ТекущийДокумент.Проведен, РежимЗаписи.Проведение, РежимЗаписи.Запись);
        
        Попытка
            ТекущийДокумент.Записать(РежимЗаписиДокумента);
            Сообщить("Документ " + СсылкаНаДокумент + " успешно обновлен.");
        Исключение
            Сообщить("Не удалось записать документ: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
        КонецПопытки;
    Иначе
        Сообщить("В документе " + СсылкаНаДокумент + " отсутствует табличная часть Расшифровка платежа!");
    КонецЕсли;
КонецЕсли;

Сценарий Б. Программное создание нового документа с заполнением ТЧ

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


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

// Добавляем строку в табличную часть РасшифровкаПлатежа
НоваяСтрока = НовыйДокумент.РасшифровкаПлатежа.Добавить();
НоваяСтрока.СуммаПлатежа = ОбщаяСуммаПлатежа;
НоваяСтрока.СуммаУслуг = Сумма_Услуг;
НоваяСтрока.СтатьяДвиженияДенежныхСредств = Справочники.СтатьиДвиженияДенежныхСредств.ОплатаПокупателей;

// Обязательные реквизиты для отражения комиссии банка
НоваяСтрока.СчетЗатрат = ПланыСчетов.Хозрасчетный.ПрочиеРасходы;
НоваяСтрока.ПрочиеДоходыИРасходы = Справочники.ПрочиеДоходыИРасходы.РасходыНаУслугиБанков;

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

Дополнительные важные нюансы при работе с реквизитами

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

Таким образом, понимание принципов нормализации данных в 1С и механизмов работы обработчиков событий позволяет быстро находить причины подобных ошибок и писать надежный, поддерживаемый программный код.

← На главную