Ошибка «Не найден объект расчетов для договора» при программном создании поступления: причины и решение

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

При переходе к разработке на современных конфигурациях 1С, таких как «Управление торговлей 11», «Комплексная автоматизация 2» или «ERP Управление предприятием», программисты часто сталкиваются с ошибками при проведении документов, созданных программно. Для этого есть модуль интеграции 1С с маркетплейсами. Одна из самых распространенных проблем — сообщение «Не найден объект расчетов для договора», хотя сам договор в документе заполнен корректно.

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

Суть проблемы и анализ кода

Рассмотрим ситуацию на примере. Разработчик пишет обработку для загрузки накладных от маркетплейсов (Wildberries, Ozon, Яндекс.Маркет). В задачах, где требуется автоматическая загрузка из Excel/CSV с созданием документа поступления, при создании документа ПриобретениеТоваровУслуг часто используется следующий код:


НовоеПоступление = Документы.ПриобретениеТоваровУслуг.СоздатьДокумент();
НовоеПоступление.Дата = ТекущаяДата();
НовоеПоступление.Партнер = Объект.Поставщик;
// ... заполнение организации, склада и прочего ...
НовоеПоступление.Договор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Закупка1", Истина);
НовоеПоступление.Записать();

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

Давайте разберемся, почему так происходит.

Архитектурные отличия: Договор vs Объект расчетов

В старых конфигурациях (например, УТ 10.3 или БП 3.0) основным разрезом взаиморасчетов был Договор. Если поле Договор заполнено, система знала, куда писать движения по регистрам.

В современных решениях (УТ 11, КА 2, ERP) архитектура сложнее. В регистрах накопления (таких как РасчетыСПоставщиками) существует измерение Объект расчетов. Это измерение является определяющим для системы, и именно по нему строится реестр платежей поставщикам с детализацией по документам и объектам расчетов.

Важно понимать, что Объект расчетов — это не всегда договор. В зависимости от настроек договора, объектом расчетов может выступать:

  1. Сам договор (если расчеты ведутся «По договорам»).
  2. Заказ поставщику (если расчеты ведутся «По заказам»).
  3. Документ поступления (если расчеты ведутся «По накладным»).

В документе ПриобретениеТоваровУслуг есть скрытый реквизит ОбъектРасчетов. Когда пользователь работает вручную, при выборе договора срабатывает событийный обработчик ПриИзменении, который анализирует настройки договора и автоматически заполняет скрытый реквизит ОбъектРасчетов.

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

Решение 1: Явное заполнение объекта расчетов

Самый простой способ исправить ошибку, если мы точно знаем, что расчеты по данному договору ведутся «По договорам», — это продублировать ссылку на договор в реквизит объекта расчетов.

Дополним код следующим образом:


// Находим договор
ТекДоговор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Закупка1", Истина);

If ЗначениеЗаполнено(ТекДоговор) Тогда
    НовоеПоступление.Договор = ТекДоговор;
    
    // ВАЖНО: Заполняем объект расчетов явно
    // Это работает, если детализация расчетов в договоре стоит "По договорам"
    НовоеПоступление.ОбъектРасчетов = ТекДоговор; 
КонецЕсли;

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


НовоеПоступление.УстановитьСсылкуНового(Документы.ПриобретениеТоваровУслуг.ПолучитьСсылку());
// ... заполнение реквизитов ...
НовоеПоступление.ОбъектРасчетов = НовоеПоступление.Ссылка;

Решение 2: Использование механизмов конфигурации (Рекомендуемый способ)

Чтобы не гадать, какой именно объект должен попасть в реквизит (договор, заказ или накладная), правильнее использовать типовые механизмы заполнения. В УТ 11 и ERP существует общий модуль для работы с взаиморасчетами.

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

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

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


НовоеПоступление = Документы.ПриобретениеТоваровУслуг.СоздатьДокумент();
// ...
НовоеПоступление.ХозяйственнаяОперация = Перечисления.ХозяйственныеОперации.ЗакупкаУПоставщика;
НовоеПоступление.Партнер = Объект.Поставщик;
НовоеПоступление.Контрагент = Объект.Поставщик; // Часто требуется заполнить и контрагента
НовоеПоступление.Организация = Объект.Организация;

// Заполняем договор
НовоеПоступление.Договор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Закупка1", Истина);

// Если используются соглашения, их тоже ОБЯЗАТЕЛЬНО нужно заполнять
// НовоеПоступление.Соглашение = ...; 

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

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

Важные замечания по коду

Помимо основной ошибки с объектом расчетов, в исходном примере есть несколько моментов, которые следует улучшить для стабильной работы.

1. Поиск по наименованию

Использование НайтиПоНаименованию("Закупка1") — это "мина замедленного действия". Как только пользователь исправит название договора на "Закупка 1" (с пробелом) или "Основной договор", ваша обработка перестанет работать. Рекомендуем искать договоры по:

2. Заполнение валют

В коде автора используется поиск валюты по коду внутри цикла (предположительно):


НовоеПоступление.Валюта = Справочники.Валюты.НайтиПоКоду("643");

Это создает лишнюю нагрузку на базу данных. Правильнее получить ссылку на рубли один раз перед началом создания документов или использовать кэшированные значения:


ВалютаРубль = Константы.ВалютаРегламентированногоУчета.Получить();
// ...
НовоеПоступление.Валюта = ВалютаРубль;

3. Использование Соглашений

В коде автора полностью игнорируется реквизит Соглашение. В УТ 11 использование соглашений может быть обязательным. Если в настройках системы включена опция «Использовать соглашения с поставщиками», то незаполненное соглашение также приведет к ошибкам проведения или некорректному заполнению цен. Чтобы избежать таких проблем при работе с документами закупки, удобно использовать рабочее место отдела закупок – цены предыдущих поставок.

Итог

Ошибка «Не найден объект расчетов» возникает из-за того, что при программном создании документа не заполняется служебный реквизит ОбъектРасчетов, который в интерфейсе заполняется автоматически.

Для исправления ситуации необходимо:

  1. Проверить настройки договора (как ведутся расчеты: по договору, по заказам или по накладным).
  2. В коде после присвоения договора явно присвоить значение реквизиту ОбъектРасчетов (ссылку на договор или на сам документ).
  3. Убедиться, что заполнены смежные реквизиты, такие как Соглашение и Контрагент.

Чтобы проверить корректность отражения данных в учете, рекомендуем использовать анализ продаж и оплат по объектам расчётов или сформировать подробный реестр оплат от покупателей с детализацией по документам и объектам расчетов.

← На главную