Почему возникает ошибка при поиске договора контрагента по наименованию и как правильно это сделать в 1С?

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

При работе с системой 1С мы часто сталкиваемся с необходимостью найти нужный договор контрагента. Казалось бы, что может быть проще, чем найти его по наименованию? Однако, как показывает практика, такой подход нередко приводит к ошибкам и нежелательным результатам. В этой статье мы с вами подробно разберем, почему поиск договора по наименованию — это не всегда лучший выбор, выясним причину распространенной ошибки синтаксиса и, главное, рассмотрим надежные и эффективные методы поиска договоров в 1С.

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

Распространенная ошибка при использовании метода НайтиПоНаименованию()

Многие разработчики и пользователи, пытаясь найти договор программно, обращаются к методу НайтиПоНаименованию() справочника ДоговорыКонтрагентов. Однако, если не учесть специфику этого справочника, можно столкнуться с ошибкой.

Рассмотрим типовой пример некорректного вызова:


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

В данном случае проблема заключается в неправильной передаче параметров. Метод НайтиПоНаименованию() для справочников, подчиненных другому справочнику (как ДоговорыКонтрагентов подчинен Контрагенты), имеет четыре параметра:

  1. <Наименование>: Строка, наименование элемента, который мы ищем.
  2. <ТочноеСоответствие>: Булево, указывает, нужен ли точный поиск.
  3. <Родитель>: Ссылка на элемент-родитель.
  4. <Владелец>: Ссылка на элемент-владелец.

Для справочника ДоговорыКонтрагентов в качестве Родителя и Владельца выступает именно Контрагент. Если мы не указываем эти параметры или указываем их неверно, система не сможет однозначно определить, среди договоров какого контрагента нужно производить поиск, и в лучшем случае вернет Неопределено, а в худшем — вызовет ошибку.

Исправленный синтаксис будет выглядеть так:


// Правильный вызов метода НайтиПоНаименованию()
// Предположим, что у нас есть ссылка на нужного Контрагента
СсылкаНаКонтрагента = пко.Контрагент; // Или получаем ее другим способом

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

Здесь мы явно указываем, что поиск должен производиться среди договоров, владельцем и родителем которых является СсылкаНаКонтрагента. Параметр Истина означает, что мы ищем точное совпадение по наименованию.

Почему поиск по наименованию — "моветон"?

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

  1. Ненадежность из-за дубликатов: В реальной жизни очень часто встречаются ситуации, когда у одного контрагента может быть несколько договоров с абсолютно одинаковым наименованием, например, "Основной договор".
    • Один "Основной договор" может быть "С покупателем" в рублях.
    • Другой "Основной договор" — "С поставщиком" в рублях.
    • Третий — "С поставщиком" в евро.
    Если мы будем искать по наименованию, система найдет первый попавшийся договор, что может привести к выбору неверного договора и, как следствие, к ошибкам в учете.
  2. Жесткая привязка к строковым значениям: Наименования могут меняться. Пользователь может переименовать договор, и ваш код, завязанный на конкретную строковую константу, перестанет работать.
  3. Отсутствие контекста: Наименование договора само по себе не несет информации о его виде (покупка, продажа), валюте, организации, с которой он заключен, и других важных параметрах.

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

Надежные методы поиска договоров контрагентов

Давайте рассмотрим, как правильно и надежно искать договоры контрагентов, учитывая все особенности системы 1С.

1. Использование механизма "Основной договор"

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

Как установить "Основной договор" вручную:

  1. Откройте карточку нужного Контрагента.
  2. Перейдите на вкладку "Договоры".
  3. Выберите нужный договор из списка.
  4. Нажмите кнопку "Использовать как основной" (или аналогичную, в зависимости от конфигурации).

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

Как получить "Основной договор" программно:

Программно получить основной договор можно, обратившись к регистру сведений ОсновныеДоговорыКонтрагента. Этот регистр хранит информацию о том, какой договор является основным для конкретной связки "Организация - Контрагент".

2. Поиск через регистр сведений "ОсновныеДоговорыКонтрагента"

Это один из наиболее надежных способов программного получения основного договора. Регистры сведений — это мощный механизм 1С для хранения данных в разрезе нескольких измерений.

Рассмотрим, как мы можем получить основной договор из этого регистра с помощью запроса.

Пример кода для получения основного договора из регистра сведений:


// Предположим, у нас есть ссылка на Контрагента и Организацию
Перем СсылкаНаКонтрагента;
Перем СсылкаНаОрганизацию;
Перем ОсновнойДоговор;

// ... получаем СсылкаНаКонтрагента и СсылкаНаОрганизацию ...
// Например:
// СсылкаНаКонтрагента = Справочники.Контрагенты.НайтиПоКоду("000000001");
// СсылкаНаОрганизацию = Справочники.Организации.НайтиПоКоду("000000001");

Если СсылкаНаКонтрагента <> Неопределено И СсылкаНаОрганизацию <> Неопределено Тогда

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

    Запрос.УстановитьПараметр("Контрагент", СсылкаНаКонтрагента);
    Запрос.УстановитьПараметр("Организация", СсылкаНаОрганизацию);
    // Важно: если нужен основной договор определенного вида, указываем его
    // Например, для договора с покупателем
    Запрос.УстановитьПараметр("ВидДоговора", Перечисления.ВидыДоговоровКонтрагентов.СПокупателем); 
    // Если вид договора не важен или нужен любой основной, 
    // можно исключить этот параметр из запроса и условия ГДЕ.

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

    Если Выборка.Следующий() Тогда
        ОсновнойДоговор = Выборка.ДоговорКонтрагента;
        Сообщить("Найден основной договор: " + ОсновнойДоговор);
    Иначе
        Сообщить("Основной договор для контрагента " + СсылкаНаКонтрагента + " и организации " + СсылкаНаОрганизацию + " не найден.");
    КонецЕсли;

Иначе
    Сообщить("Не удалось получить ссылки на контрагента или организацию.");
КонецЕсли;

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

Также возможно программно создать договор и сделать его основным, добавив соответствующую запись в регистр сведений ОсновныеДоговорыКонтрагента.

3. Поиск по другим реквизитам или через запрос

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

Ключевые реквизиты, по которым можно искать договор:

  1. Контрагент: Ссылка на контрагента, которому принадлежит договор. Это обязательный и самый важный фильтр.
  2. ВидДоговора: Тип договора (СПокупателем, СПоставщиком, Прочее и т.д.).
  3. ВалютаВзаиморасчетов: Валюта, в которой ведутся расчеты по договору.
  4. Организация: Наша организация, от имени которой заключен договор.
  5. Номер и Дата: Номер и дата договора.

Пример запроса для поиска договора по нескольким параметрам:


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

// ... получаем СсылкаНаКонтрагента, СсылкаНаОрганизацию, ИскомыйВидДоговора, ИскомаяВалюта ...

Если СсылкаНаКонтрагента <> Неопределено И СсылкаНаОрганизацию <> Неопределено Тогда

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    ДоговорыКонтрагентов.Ссылка
        |ИЗ
        |    Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
        |ГДЕ
        |    ДоговорыКонтрагентов.Владелец = &Контрагент
        |    И ДоговорыКонтрагентов.Организация = &Организация
        |    И ДоговорыКонтрагентов.ВидДоговора = &ВидДоговора
        |    И ДоговорыКонтрагентов.ВалютаВзаиморасчетов = &Валюта
        |    И ДоговорыКонтрагентов.Наименование = &Наименование"; // Можно добавить наименование, но лучше избегать
        
    Запрос.УстановитьПараметр("Контрагент", СсылкаНаКонтрагента);
    Запрос.УстановитьПараметр("Организация", СсылкаНаОрганизацию);
    Запрос.УстановитьПараметр("ВидДоговора", ИскомыйВидДоговора);
    Запрос.УстановитьПараметр("Валюта", ИскомаяВалюта);
    Запрос.УстановитьПараметр("Наименование", "Основной договор"); // Используем как дополнительный фильтр, если уверены

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

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

Иначе
    Сообщить("Не удалось получить ссылки на контрагента или организацию.");
КонецЕсли;

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

Важные аспекты договоров в 1С

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

1. Справочник "ДоговорыКонтрагентов"

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

Понимание структуры этого справочника поможет нам эффективнее строить запросы и работать с договорами.

2. "Вид договора" и "Валюта"

Мы уже упоминали эти реквизиты, но давайте подчеркнем их важность:

Все эти параметры настраиваются в карточке договора в справочнике ДоговорыКонтрагентов.

3. Множество договоров с одним контрагентом

Система 1С позволяет вести учет нескольких договоров с одним и тем же контрагентом. Как мы уже выяснили, они могут отличаться не только номерами и датами, но и ВидомДоговора, Валютой, Организацией и другими условиями. Это нормальная практика, и именно поэтому поиск по наименованию является ненадежным.

Заключение

Мы с вами подробно рассмотрели проблему поиска договоров контрагентов в 1С. Выяснили, что хотя метод НайтиПоНаименованию() и может быть использован с корректным синтаксисом, он является ненадежным и нерекомендуемым подходом из-за потенциальных дубликатов и жесткой привязки к строковым значениям.

Вместо этого мы настоятельно рекомендуем использовать:

  1. Механизм "Основной договор" через регистр сведений ОсновныеДоговорыКонтрагента для получения договора, установленного как основной.
  2. Прямые запросы к справочнику ДоговорыКонтрагентов с использованием фильтрации по Контрагенту, Организации, ВидуДоговора, ВалютеВзаиморасчетов и другим специфическим реквизитам.

Эти подходы обеспечат точность, надежность и гибкость вашего кода, что является залогом корректной и стабильной работы системы 1С.

← К списку