При переносе данных с помощью Конвертации данных 2.1 (КД 2.1) программисты часто сталкиваются с ситуациями, когда стандартные механизмы загрузки дополняются сложным программным кодом в обработчиках. Одной из наиболее «коварных» ошибок в современных конфигурациях на базе платформы 1С:Предприятие 8.3 (таких как ERP 2.5, Комплексная автоматизация 2 или Управление торговлей 11) является ошибка: «Не удалось найти объект расчетов. Код ошибки = 21».
Эта ошибка обычно возникает в момент вызова метода Записать() для объекта справочника ДоговорыКонтрагентов. Давайте подробно разберем, почему это происходит и как правильно настроить обмен, чтобы избежать подобных исключений.
Рассмотрим ситуацию, описанную пользователем. В обработчике «После загрузки» правила конвертации объектов (ПКО) выполняется программное создание или поиск основного договора для контрагента. Код выглядит следующим образом:
// Получение параметров, переданных из источника
ДатаДоговора = ПараметрыОбъекта.Получить("ДатаДоговора");
СрокДействия = ПараметрыОбъекта.Получить("СрокДействия");
НомерДоговора = ПараметрыОбъекта.Получить("НомерДоговора");
ВалютаВзаиморасчетов = ПараметрыОбъекта.Получить("ВалютаВзаиморасчетов");
Владелец = ПараметрыОбъекта.Получить("Владелец");
ВедениеВзаиморасчетов = ПараметрыОбъекта.Получить("ВедениеВзаиморасчетов");
// Поиск или создание Партнера
КонтрагентНаименование = Владелец.Наименование;
ПартнерСсылка = Справочники.Партнеры.НайтиПоРеквизиту("НаименованиеПолное", КонтрагентНаименование);
Партнер = ПартнерСсылка.ПолучитьОбъект();
// Логика создания договора
Если ДоговорПроверка = Справочники.БУХ_ДоговорыКонтрагентов.ПустаяСсылка() Тогда
ОсновнойДоговор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
Иначе
// ... логика поиска существующего договора
КонецЕсли;
// Заполнение реквизитов договора
ОсновнойДоговор.Наименование = Объект.Наименование;
// ... установка типов договора и порядка расчетов
ОсновнойДоговор.Записать(); // Здесь возникает ошибка Код 21
Проанализируем причину сбоя. В современных конфигурациях 1С используется сложная подсистема взаиморасчетов. Когда мы вызываем Записать() для договора, система автоматически пытается создать запись в техническом справочнике «Объекты расчетов» (или связать договор с существующим ключом). Код ошибки 21 сигнализирует о том, что внутренняя функция подсистемы не смогла идентифицировать параметры для формирования этого ключа.
Это самая распространенная причина. Когда объект создается или загружается через стандартные механизмы КД 2.1, платформа автоматически устанавливает свойство ОбменДанными.Загрузка = Истина. Это отключает большинство проверок в модуле объекта и модуле менеджера, позволяя записать «сырые» данные.
Однако, в приведенном выше коде автор создает объект вручную через Справочники.ДоговорыКонтрагентов.СоздатьЭлемент(). Для такого объекта свойство ОбменДанными.Загрузка по умолчанию равно Ложь. Следовательно, при вызове Записать() система запускает полную бизнес-логику, включая механизмы онлайн-взаиморасчетов, которые требуют идеальной заполненности всех связанных аналитик.
Решение: Перед вызовом записи необходимо принудительно установить признак загрузки.
ОсновнойДоговор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
// ... заполнение полей ...
ОсновнойДоговор.ОбменДанными.Загрузка = Истина;
ОсновнойДоговор.Записать();
Разберем ситуацию глубже. Даже если мы установим Загрузка = Ложь, запись должна проходить, если все данные корректны. Ошибка 21 часто возникает, когда для формирования объекта расчетов не хватает ключевого поля — Организации.
В коде автора мы видим заполнение контрагента, партнера и валюты, но отсутствует явное указание организации. В ERP и УТ 11 договор жестко привязан к организации. Если подсистема расчетов видит пустую организацию, она не может инициализировать расчетный ключ. Выясним, почему это критично: объект расчетов — это «точка сборки» всех движений по регистрам. Нет организации — нет учета.
Решение: Убедитесь, что реквизит ОсновнойДоговор.Организация заполнен корректной ссылкой до момента вызова Записать().
В коде есть условие на заполнение реквизита ПорядокРасчетов:
Если ВедениеВзаиморасчетов = 1 Тогда
ОсновнойДоговор.ПорядокРасчетов = Перечисления.ПорядокРасчетов.ПоДоговорамКонтрагентов;
Иначе
ОсновнойДоговор.ПорядокРасчетов = Перечисления.ПорядокРасчетов.ПоНакладным;
КонецЕсли;
Если выбран порядок «По договорам», то сам договор становится объектом расчетов. В этом случае требования системы к его корректности возрастают в разы. Ошибка 21 в данном контексте означает, что система попыталась зарегистрировать этот договор в реестре объектов расчетов, но произошел внутренний отказ (например, из-за несоответствия типа договора и типа партнера).
Чтобы избежать ошибок при программном создании объектов в обработчиках КД 2.1, рекомендуем придерживаться следующей последовательности действий:
Партнер, затем Контрагент (Владелец), и только потом Договор.ОбменДанными.Загрузка = Истина. Это сэкономит время и избавит от лишних проверок.Загрузка = Ложь, после записи может потребоваться вызов серверных процедур для обновления иерархии или аналитики (например, модули ВзаиморасчетыСервер).Проанализируем, как должен выглядеть фрагмент кода, чтобы ошибка 21 гарантированно исчезла:
// Создаем новый договор
НовыйДоговор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
// Заполняем основные данные
НовыйДоговор.Наименование = "Основной договор";
НовыйДоговор.Организация = Справочники.Организации.НайтиПоНаименованию("Наша Организация");
НовыйДоговор.Контрагент = Владелец;
НовыйДоговор.Партнер = ПартнерСсылка;
НовыйДоговор.Дата = ТекущаяДата();
// Устанавливаем режим загрузки, чтобы обойти проверку "Объекта расчетов"
НовыйДоговор.ОбменДанными.Загрузка = Истина;
Попытка
НовыйДоговор.Записать();
// Передаем ссылку обратно в основной объект загрузки
Объект.Владелец = НовыйДоговор.Ссылка;
Исключение
Сообщить("Не удалось записать договор: " + ОписаниеОшибки());
КонецПопытки;
Ошибка с кодом 21 — это защитный механизм конфигураций, использующих сложную финансовую архитектуру. Она возникает тогда, когда бизнес-логика системы не может сопоставить договор с правилами ведения взаиморасчетов. Рассмотрим основные выводы:
ОбменДанными.Загрузка = Истина — это стандарт де-факто для создаваемых вручную объектов.ПередЗаписью — иногда разработчики конфигураций вставляют туда код, который игнорирует признак загрузки (хотя это и считается плохим тоном в разработке на платформе 1С).Используя эти рекомендации, вы сможете обеспечить стабильную работу ваших правил обмена и избежать прерывания загрузки на сложных участках кода.