Как программно найти и заполнить договор контрагента с учетом вида договора

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

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

Проблема стандартного метода НайтиПоНаименованию

Рассмотрим ситуацию: вы используете стандартный метод Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию(НужныйКонтрагент). Этот подход имеет два существенных недостатка. Во-первых, если у контрагента два договора (например, основной для покупок и основной для продаж), система вернет первый попавшийся. Во-вторых, без указания владельца поиск будет идти по всей базе, что может привести к подстановке договора совершенно другого контрагента — для этой задачи есть автоматический поиск договоров при загрузке банковских выписок.

Проанализируем правильные способы решения этой задачи, начиная от простых запросов и заканчивая использованием встроенных механизмов БСП (Библиотеки стандартных подсистем) — в этом поможет автоматическое заполнение аналитики и договоров в отражении зарплаты.

Способ 1. Поиск договора через запрос с фильтрацией по виду

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

Рассмотрим пример реализации такой функции:


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

    Запрос.УстановитьПараметр("Контрагент", Контрагент);
    Запрос.УстановитьПараметр("Наименование", Наименование);
    Запрос.УстановитьПараметр("Организация", Организация);
    Запрос.УстановитьПараметр("ТипДоговора", ТипДоговора);

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

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

Чтобы вызвать эту функцию для получения договора с покупателем, используем следующий код:


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

Способ 2. Использование типовых функций (БСП)

В современных конфигурациях, таких как BAS Бухгалтерия 2.1 или 1С:Бухгалтерия 3.0, многие задачи уже решены в общих модулях. Выясним, какие инструменты мы можем использовать, чтобы не «изобретать велосипед».

  1. Получение договора по умолчанию: В модуле РаботаСДоговорамиКонтрагентов часто существует функция ПолучитьДоговорПоУмолчанию. Она полезна, когда в базе один из договоров помечен как основной — для этого есть обработка автоматической подстановки основного договора.
  2. Установка договора в документ: Метод РаботаСДоговорамиКонтрагентовБП.УстановитьДоговорКонтрагента автоматически подберет подходящий договор, исходя из типа операции документа.

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


ПараметрыДоговора = РаботаСДоговорамиКонтрагентов.ПараметрыДляПолученияДоговораПоУмолчанию();
ПараметрыДоговора.Контрагент = ТекущийКонтрагент;
ПараметрыДоговора.Организация = Объект.Организация;
ПараметрыДоговора.ВидДоговора = Перечисления.ВидыДоговоровКонтрагентов.СПоставщиком;

ДоговорСсылка = РаботаСДоговорамиКонтрагентов.ПолучитьДоговорПоУмолчанию(ПараметрыДоговора);

Оптимизация при больших объемах данных

Если в вашей обработке более 800 записей, выполнение запроса в цикле для каждой строки (как показано в Способе 1) существенно замедлит работу системы. Это классическая проблема «Запрос в цикле». Посмотрим, как ускорить процесс в десятки раз:

Разберем алгоритм оптимизации:

  1. Сначала соберем всех контрагентов из вашей таблицы в один массив (используя метод ВыгрузитьКолонку()).
  2. Выполним один запрос ко всему справочнику ДоговорыКонтрагентов с условием ГДЕ Контрагент В (&МассивКонтрагентов).
  3. Результат запроса выгрузим в Соответствие, где ключом будет Контрагент, а значением — Ссылка на договор.
  4. В основном цикле будем просто получать готовый договор из соответствия по ключу-контрагенту.

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


// 1. Собираем контрагентов
МассивКнт = ТаблицаДанных.ВыгрузитьКолонку("Контрагент");

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

Запрос.УстановитьПараметр("МассивКнт", МассивКнт);
Запрос.УстановитьПараметр("ВидДоговора", Перечисления.ВидыДоговоровКонтрагентов.СПокупателем);

ТаблицаДоговоров = Запрос.Выполнить().Выгрузить();

// 3. Создаем соответствие для быстрого доступа
КэшДоговоров = Новый Соответствие;
Для Каждого Стр Из ТаблицаДоговоров Цикл
    КэшДоговоров.Вставить(Стр.Контрагент, Стр.Ссылка);
КонецЦикла;

// 4. Используем в цикле
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    СтрокаТЧ.Договор = КэшДоговоров.Получить(СтрокаТЧ.Контрагент);
КонецЦикла;

Важные нюансы: Валюта и Организация

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

Автоматическое создание договора

Если поиск не дал результатов, логично предусмотреть автоматическое создание договора прямо из обработки. Это избавит пользователя от рутины — удобнее через автоматический подбор договоров и аналитики при загрузке выписки. Проанализируем пример кода для создания нового элемента:


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

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

← На главную