Как исправить ошибку «Несоответствие типов (параметр номер '2')» при поиске договора контрагента?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В этой статье мы подробно разберем распространенную ошибку, возникающую у начинающих программистов 1С при работе с подчиненными справочниками. Часто при переносе логики из старых версий (7.7) или при недостаточном внимании к синтаксису возникает исключение при попытке программно найти элемент справочника.

Рассмотрим конкретную ситуацию: необходимо найти договор с наименованием "Основной договор", принадлежащий определенному контрагенту. Код, вызывающий ошибку, выглядит следующим образом:


Договор = Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию("Основой договор", пко.Контрагент);

При выполнении этого кода система выдает ошибку:

Ошибка при вызове метода контекста (НайтиПоНаименованию): Несоответствие типов (параметр номер '2').

Давайте проанализируем причины и найдем правильное решение.

Разбор причин ошибки

Чтобы понять суть проблемы, обратимся к синтаксису метода НайтиПоНаименованию. В платформе 1С:Предприятие 8 этот метод имеет строго определенный порядок параметров:


СправочникМенеджер.<Имя справочника>.НайтиПоНаименованию(<Наименование>, <ТочноеСоответствие>, <Родитель>, <Владелец>)

Разберем назначение каждого параметра по порядку:

  1. Наименование (Строка) — текст, который мы ищем.
  2. ТочноеСоответствие (Булево) — определяет режим поиска. Если Истина, ищется полное совпадение строки. Если Ложь — поиск по вхождению (начинается с...).
  3. Родитель (СправочникСсылка) — используется для поиска внутри определенной группы (папки) в иерархических справочниках.
  4. Владелец (СправочникСсылка) — используется для отбора элементов по владельцу в подчиненных справочниках.

Теперь посмотрим на ошибочный код:


// ОШИБКА:
.НайтиПоНаименованию("Основой договор", пко.Контрагент);

Мы видим, что вторым параметром передается ссылка на контрагента (пко.Контрагент). Однако система ожидает там значение типа Булево (Истина или Ложь). Именно поэтому возникает ошибка несоответствия типов.

Справочник ДоговорыКонтрагентов подчинен справочнику Контрагенты. Это означает, что контрагент является Владельцем договора, а не Родителем (родитель — это папка внутри договоров) и не флагом точности поиска.

Правильное решение (Исправление синтаксиса)

Чтобы код заработал корректно, нам нужно передать контрагента в четвертый параметр. Третий параметр (Родитель) в данном случае нам не нужен, поэтому мы его пропускаем.

Скорректированный код будет выглядеть так:


// Правильный вызов:
// 1. Имя
// 2. Точное соответствие (Истина)
// 3. Родитель (пропускаем)
// 4. Владелец (наш контрагент)

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

Обратите внимание на две запятые подряд , , — это означает, что третий параметр оставлен пустым.

Рекомендации по оптимизации и надежности

Хотя исправление синтаксиса решит техническую ошибку, профессиональный подход требует более глубокого анализа задачи. Поиск договора по наименованию (строке "Основной договор") считается ненадежной практикой ("моветоном") по нескольким причинам:

  1. Опечатки: Пользователь мог назвать договор "Осн. договор", "Основной договор " (с пробелом) или "Договор поставки", и ваш поиск вернет пустую ссылку.
  2. Дубли: У контрагента может быть несколько договоров с одинаковым названием (например, старый закрытый и новый). Метод НайтиПоНаименованию вернет первый попавшийся, который может быть помечен на удаление.
  3. Разные виды договоров: Один контрагент может быть и поставщиком, и покупателем. У него могут быть разные договоры для разных организаций и валют.

Альтернативный способ №1: Использование реквизита "Основной договор"

Во многих типовых конфигурациях (например, Управление Торговлей, Бухгалтерия) у самого справочника Контрагенты есть реквизит ОсновнойДоговор. Это ссылка на справочник договоров.

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


// Пробуем взять договор, назначенный основным у контрагента
НайденныйДоговор = пко.Контрагент.ОсновнойДоговор;

Если НайденныйДоговор.Пустая() Тогда
    // Если основного нет, тогда уже пробуем искать или создаем новый
    // ... логика поиска ...
КонецЕсли;

Альтернативный способ №2: Использование Запроса

Для массовых загрузок данных или сложной логики (когда нам нужен договор с определенной валютой и видом) лучше использовать Запрос. Это позволит исключить помеченные на удаление элементы и учесть дополнительные параметры.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	Договоры.Ссылка КАК Ссылка
    |ИЗ
    |	Справочник.ДоговорыКонтрагентов КАК Договоры
    |ГДЕ
    |	Договоры.Владелец = &Владелец
    |	И Договоры.Наименование ПОДОБНО &Наименование
    |	И НЕ Договоры.ПометкаУдаления
    |	И Договоры.ВидДоговора = &ВидДоговора";

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

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

Используя эти методы, вы не только избежите ошибок типов данных, но и сделаете ваш код устойчивым к изменениям данных в базе.

← На главную