В процессе ведения учета в программе 1С часто возникают ситуации, когда требуется исправить ошибки прошлых периодов. Одна из классических и весьма болезненных задач — необходимость изменить контрагента у существующих договоров, по которым уже зарегистрированы хозяйственные операции. Особенно остро эта проблема встает, когда документы относятся к закрытому периоду (например, прошлым годам), отчетность по которому сдана, а перепроведение документов категорически запрещено.
В этой статье мы подробно разберем, почему стандартные инструменты блокируют такое изменение, к каким скрытым и опасным последствиям может привести прямой обход блокировок, а также рассмотрим безопасные технические и методологические способы решения данной задачи.
Прежде чем переходить к техническим действиям, проанализируем архитектуру хранения данных в платформе 1С. В типовых конфигурациях (таких как 1С:Бухгалтерия предприятия) справочник ДоговорыКонтрагентов является подчиненным справочнику Контрагенты. Это означает, что контрагент выступает физическим владельцем записи договора в базе данных.
Если мы попытаемся открыть карточку договора и вручную изменить поле владельца (или воспользуемся стандартной обработкой «Групповое изменение реквизитов»), система выдаст ошибку и заблокирует запись. Это происходит из-за встроенной логики контроля целостности данных. В модуле объекта справочника ДоговорыКонтрагентов в обработчике события ПередЗаписью прописана проверка:
Процедура ПередЗаписью(Отказ)
Если ЭтоНовый() Тогда
Возврат;
КонецЕсли;
// Проверка, изменился ли владелец договора
СсылкаНаВладельца = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Владелец");
Если Владелец <> СсылкаНаВладельца Тогда
// Проверка наличия движений по договору в регистрах
Если ЕстьДвиженияПоДоговору(Ссылка) Тогда
ВызватьИсключение "Невозможно изменить владельца договора, так как по нему уже зарегистрированы документы!";
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Эта проверка защищает базу данных от рассинхронизации. Платформа 1С «понимает», что если изменить владельца договора, то во всех проведенных ранее документах возникнет логическое противоречие.
Выясним причину, почему разработчики 1С наложили столь жесткое ограничение. Предположим, мы обошли программную блокировку и принудительно перезаписали владельца договора «Договор №1» с Контрагента «А» на Контрагента «Б» без перепроведения первичных документов за 2019 год.
В бухгалтерском учете на счетах расчетов с контрагентами (например, счета 60, 62, 76) используется аналитика (субконто):
Контрагенты).ДоговорыКонтрагентов).Поскольку мы не перепроводили документы, в регистре бухгалтерии (в проводках) физически остались старые записи. В поле первого субконто там по-прежнему записана ссылка на Контрагента «А», а во втором субконто — ссылка на наш «Договор №1». Однако теперь этот договор в справочнике принадлежит Контрагенту «Б».
Проанализируем последствия такого состояния системы:
Если перед вами стоит задача исправить дубли или некорректно заведенных контрагентов в закрытом периоде и руководство осознает все риски, технически изменить владельца договора без перепроведения документов можно с помощью отключения проверок бизнес-логики.
Для этого программисты используют установку флага ОбменДанными.Загрузка = Истина при записи объекта. В таком режиме платформа игнорирует обработчик ПередЗаписью. Для такого действия подойдёт групповая обработка с поддержкой режима загрузки данных.
Рассмотрим пример кода внешней обработки, выполняющей такое изменение:
&НаСервере
Процедура ИзменитьВладельцаДоговораНаСервере(СсылкаНаДоговор, НовыйВладелецСсылка)
ДоговорОбъект = СсылкаНаДоговор.ПолучитьОбъект();
ДоговорОбъект.Владелец = НовыйВладелецСсылка;
// Включаем режим загрузки данных для обхода встроенных проверок модуля
ДоговорОбъект.ОбменДанными.Загрузка = Истина;
Попытка
ДоговорОбъект.Записать();
Сообщить("Владелец договора успешно изменен в справочнике.");
Исключение
Сообщить("Ошибка при записи договора: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Важное примечание: Использование этого метода решит проблему только на уровне самого справочника. Чтобы избежать рассинхронизации в проводках, нам потребуется программно скорректировать все движения по регистрам бухгалтерии и регистрам накопления, где фигурировал старый контрагент, без фактического перепроведения документов.
Посмотрим на пример кода, который точечно перезаписывает движения регистра бухгалтерии (субконто) для конкретного документа:
&НаСервере
Процедура КорректировкаПроводокБезПерепроведения(ДокументСсылка, СтарыйКонтрагент, НовыйКонтрагент)
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументСсылка);
НаборЗаписей.Прочитать();
Модифицирован = Ложь;
Для Каждого Запись Из НаборЗаписей Цикл
// Проверяем Субконто Дебета
Для Каждого КлючЗначение Из Запись.СубконтоДт Цикл
Если КлючЗначение.Значение = СтарыйКонтрагент Тогда
Запись.SubkontoDt[КлючЗначение.Ключ] = НовыйКонтрагент;
Модифицирован = Истина;
КонецЕсли;
КонецЦикла;
// Проверяем Субконто Кредита
Для Каждого КлючЗначение Из Запись.СубконтоКт Цикл
Если КлючЗначение.Значение = СтарыйКонтрагент Тогда
Запись.SubkontoKt[КлючЗначение.Ключ] = НовыйКонтрагент;
Модифицирован = Истина;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Если Модифицирован Тогда
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Записать();
Сообщить("Проводки документа " + ДокументСсылка + " успешно скорректированы.");
КонецЕсли;
КонецПроцедуры
Этот способ требует написания полноценной технической обработки, которая должна обходить не только регистры бухгалтерии, но и регистры накопления (например, связанные с расчетами по НДС, взаиморасчетами с клиентами и поставщиками), иначе отчетность все равно «поплывет». Для этой задачи можно использовать инструмент для точечного редактирования реквизитов и движений регистров.
Методологически правильным и полностью безопасным решением, не требующим вмешательства программиста и написания опасных обработок, является использование штатных механизмов конфигурации.
Если контрагент действительно изменился (например, произошло слияние компаний, реорганизация, уступка прав требования или перевод долга), бухгалтер должен зафиксировать это событие текущей датой в открытом периоде с помощью документа Корректировка долга.
Разберем по шагам, как правильно выполнить эту операцию:
Результат: Все исторические данные за 2019 год и прошлые периоды остаются нетронутыми. Баланс сходится, закрытые периоды в безопасности. Начиная с даты проведения корректировки долга, все расчеты переходят на нового контрагента и его новый договор. Этот метод является единственным законным с точки зрения аудита и налоговых проверок.
Проанализируем ремарку из обсуждения на форуме касаемо современных конфигураций на базе ERP-платформ (например, 1С:Управление торговлей 11, 1С:Комплексная автоматизация 2). В этих системах архитектура справочников претерпела существенные изменения:
ДоговорыМеждуОрганизациями или ДоговорыКонтрагентов больше не является подчиненным справочнику Контрагенты.С технической точки зрения изменить контрагента в договоре в этих программах значительно проще, система не заблокирует запись элемента справочника намертво на уровне платформы. Однако логическая проблема рассинхронизации данных в регистрах расчетов остается абсолютно идентичной. Если вы поменяете контрагента в независимом договоре, существующие движения документов по регистрам накопления (таким как РасчетыСКлиентами, РасчетыСПоставщиками) продолжат ссылаться на старого контрагента, что приведет к полному разрушению партионного учета и расчетов в текущем периоде. Поэтому правила предосторожности здесь действуют те же самые.
Подводя итог обсуждению, дадим несколько ключевых советов для администраторов и программистов 1С: