Как программно или массово изменить договор в документе «Списание с расчетного счета»?

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

В процессе сопровождения баз 1С часто возникает задача массовой корректировки данных в уже проведенных документах. Одной из наиболее коварных операций является смена договора в документе Списание с расчетного счета. Начинающие разработчики часто сталкиваются с ситуацией, когда код вроде бы написан верно, отладчик показывает присвоение значения, но после записи документа изменения не сохраняются или «слетают». В этой статье мы подробно разберем, почему так происходит, проанализируем структуру документа и выработаем правильный алгоритм решения задачи.

Разбор типичных ошибок в программном коде

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


Пока ВыборкаДокументов.Следующий() Цикл
    Док = ВыборкаДокументов.Ссылка.ПолучитьОбъект();
    Если ВыборкаДокументов.Ссылка.ПолучитьОбъект().Контрагент <> Неопределено Тогда
        // ... логика изменения
    КонецЕсли;
КонецЦикла;

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

Во-вторых, проверка на Неопределено для ссылочных типов (таких как Контрагент) не совсем корректна. В 1С ссылка не может быть Неопределено, она может быть либо пустой, либо указывать на конкретный элемент. Правильнее использовать метод ПустаяСсылка().

Почему договор не сохраняется: ищем «невидимые» реквизиты

Главная причина, по которой программная замена договора в шапке документа Списание с расчетного счета часто не дает результата, кроется в архитектуре современных конфигураций (например, Бухгалтерия предприятия 3.0 или ERP). Проанализируем структуру данных этого документа.

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

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

Правильный алгоритм программного изменения договора

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


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

Использование стандартной обработки «Групповое изменение реквизитов»

Если вам нужно разово поменять договоры и вы не хотите писать код, рассмотрим стандартный инструмент 1С — обработку Групповое изменение реквизитов. Она доступна в разделе «Администрирование» — «Обслуживание» — «Корректировка данных».

Однако здесь есть нюанс. Если вы просто выберете документы и попытаетесь изменить реквизит Договор, вы можете столкнуться с той же проблемой — реквизитов может быть несколько. Разберем по шагам, как сделать это правильно:

  1. Откройте обработку и выберите тип документа Списание с расчетного счета.
  2. Нажмите кнопку Дополнительные параметры и установите флажок Режим разработчика. Это критически важно, так как без этого режима табличные части могут быть скрыты.
  3. В списке реквизитов вы увидите два раздела: «Реквизиты» (это шапка) и «Расшифровка платежа» (это табличная часть).
  4. Вам необходимо найти реквизит Договор в обоих разделах и установить для них новое значение.
  5. Выполните изменение. Система сама позаботится о перезаписи и проведении документов.

Важные замечания по проверке данных

При программной смене договора обязательно проанализируем ситуацию с Владельцем. Справочник ДоговорыКонтрагентов является подчиненным справочнику Контрагенты. Рассмотрим, что произойдет, если мы по ошибке подставим договор, принадлежащий другому контрагенту. В лучшем случае система выдаст ошибку при записи, в худшем — запишет некорректные данные, что приведет к «разрыву» аналитики в бухгалтерских отчетах.

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


Если НовыйДоговор.Владелец <> ДокОбъект.Контрагент Тогда
    Сообщить("Ошибка: Выбранный договор не принадлежит контрагенту документа!");
    Возврат;
КонецЕсли;

Также выясним причину возможного сброса договора из-за Вида операции. Если в документе выбран вид операции «Оплата поставщику», а вы пытаетесь подставить договор с видом «Прочее», стандартные проверки 1С могут очистить это поле при проведении. Всегда проверяйте соответствие Вида договора хозяйственной операции документа.

В завершение отметим, что если документ находится в закрытом периоде или по нему нельзя выполнять стандартные проверки, можно использовать свойство ОбменДанными.Загрузка = Истина. Это позволит записать объект «как есть», минуя большинство встроенных обработчиков. Однако помните: в этом случае движения по регистрам (проводки) могут не обновиться автоматически, и вам потребуется перепровести документ вручную или программно.

← На главную