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