При автоматизации загрузки данных или создании внешних обработок в 1С часто возникает задача программного заполнения договоров. Обычный поиск по наименованию часто оказывается недостаточным, так как у одного контрагента может быть несколько договоров с одинаковыми именами, но разными типами — например, «С покупателем» и «С поставщиком» — для этого подойдёт обработка поиска и синхронизации договоров при загрузке из Excel. Разберем, как правильно реализовать выбор нужного договора, чтобы избежать ошибок в учете.
Рассмотрим ситуацию: вы используете стандартный метод Справочники.ДоговорыКонтрагентов.НайтиПоНаименованию(НужныйКонтрагент). Этот подход имеет два существенных недостатка. Во-первых, если у контрагента два договора (например, основной для покупок и основной для продаж), система вернет первый попавшийся. Во-вторых, без указания владельца поиск будет идти по всей базе, что может привести к подстановке договора совершенно другого контрагента — для этой задачи есть автоматический поиск договоров при загрузке банковских выписок.
Проанализируем правильные способы решения этой задачи, начиная от простых запросов и заканчивая использованием встроенных механизмов БСП (Библиотеки стандартных подсистем) — в этом поможет автоматическое заполнение аналитики и договоров в отражении зарплаты.
Самый надежный и гибкий способ — написать функцию, которая принимает все необходимые параметры (Организация, Контрагент, Тип договора) и возвращает нужную ссылку. Это позволяет нам точно указать, какой вид договора нам нужен, используя значения перечисления Перечисления.ВидыДоговоровКонтрагентов.
Рассмотрим пример реализации такой функции:
Функция НайтиДоговор(Организация, Контрагент, ТипДоговора, Наименование)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДоговорыКонтрагентов.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| НЕ ДоговорыКонтрагентов.ПометкаУдаления
| И ДоговорыКонтрагентов.Наименование = &Наименование
| И ДоговорыКонтрагентов.Организация = &Организация
| И ДоговорыКонтрагентов.Контрагент = &Контрагент
| И ДоговорыКонтрагентов.ВидДоговора = &ТипДоговора";
Запрос.УстановитьПараметр("Контрагент", Контрагент);
Запрос.УстановитьПараметр("Наименование", Наименование);
Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("ТипДоговора", ТипДоговора);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Возврат Неопределено;
Иначе
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
Возврат Выборка.Ссылка;
КонецЕсли;
КонецФункции
Чтобы вызвать эту функцию для получения договора с покупателем, используем следующий код:
ТипПокупатель = Перечисления.ВидыДоговоровКонтрагентов.СПокупателем;
НужныйДоговор = НайтиДоговор(Объект.Организация, ТекущийКонтрагент, ТипПокупатель, "Основной договор");
В современных конфигурациях, таких как BAS Бухгалтерия 2.1 или 1С:Бухгалтерия 3.0, многие задачи уже решены в общих модулях. Выясним, какие инструменты мы можем использовать, чтобы не «изобретать велосипед».
РаботаСДоговорамиКонтрагентов часто существует функция ПолучитьДоговорПоУмолчанию. Она полезна, когда в базе один из договоров помечен как основной — для этого есть обработка автоматической подстановки основного договора.РаботаСДоговорамиКонтрагентовБП.УстановитьДоговорКонтрагента автоматически подберет подходящий договор, исходя из типа операции документа.Пример использования типового механизма:
ПараметрыДоговора = РаботаСДоговорамиКонтрагентов.ПараметрыДляПолученияДоговораПоУмолчанию();
ПараметрыДоговора.Контрагент = ТекущийКонтрагент;
ПараметрыДоговора.Организация = Объект.Организация;
ПараметрыДоговора.ВидДоговора = Перечисления.ВидыДоговоровКонтрагентов.СПоставщиком;
ДоговорСсылка = РаботаСДоговорамиКонтрагентов.ПолучитьДоговорПоУмолчанию(ПараметрыДоговора);
Если в вашей обработке более 800 записей, выполнение запроса в цикле для каждой строки (как показано в Способе 1) существенно замедлит работу системы. Это классическая проблема «Запрос в цикле». Посмотрим, как ускорить процесс в десятки раз:
Разберем алгоритм оптимизации:
ВыгрузитьКолонку()).ДоговорыКонтрагентов с условием ГДЕ Контрагент В (&МассивКонтрагентов).Соответствие, где ключом будет Контрагент, а значением — Ссылка на договор.Пример реализации оптимизированного поиска:
// 1. Собираем контрагентов
МассивКнт = ТаблицаДанных.ВыгрузитьКолонку("Контрагент");
// 2. Один запрос на всех
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДоговорыКонтрагентов.Контрагент,
| ДоговорыКонтрагентов.Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| ДоговорыКонтрагентов.Контрагент В(&МассивКнт)
| И ДоговорыКонтрагентов.ВидДоговора = &ВидДоговора
| И НЕ ДоговорыКонтрагентов.ПометкаУдаления";
Запрос.УстановитьПараметр("МассивКнт", МассивКнт);
Запрос.УстановитьПараметр("ВидДоговора", Перечисления.ВидыДоговоровКонтрагентов.СПокупателем);
ТаблицаДоговоров = Запрос.Выполнить().Выгрузить();
// 3. Создаем соответствие для быстрого доступа
КэшДоговоров = Новый Соответствие;
Для Каждого Стр Из ТаблицаДоговоров Цикл
КэшДоговоров.Вставить(Стр.Контрагент, Стр.Ссылка);
КонецЦикла;
// 4. Используем в цикле
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
СтрокаТЧ.Договор = КэшДоговоров.Получить(СтрокаТЧ.Контрагент);
КонецЦикла;
При программном заполнении обязательно учитывайте следующие моменты, иначе документ может не провестись:
ДоговорыКонтрагентов.ВалютаВзаиморасчетов = &ВалютаДокумента в ваш запрос.Объект.Организация.Если поиск не дал результатов, логично предусмотреть автоматическое создание договора прямо из обработки. Это избавит пользователя от рутины — удобнее через автоматический подбор договоров и аналитики при загрузке выписки. Проанализируем пример кода для создания нового элемента:
Если ДоговорСсылка = Неопределено Тогда
НовыйДоговор = Справочники.ДоговорыКонтрагентов.СоздатьЭлемент();
НовыйДоговор.Владелец = ТекущийКонтрагент;
НовыйДоговор.Организация = Объект.Организация;
НовыйДоговор.ВидДоговора = Перечисления.ВидыДоговоровКонтрагентов.СПокупателем;
НовыйДоговор.Наименование = "Основной договор (создан автоматически)";
НовыйДоговор.ВалютаВзаиморасчетов = ПараметрыСеанса.ТекущаяВалютаБухгалтерскогоУчета;
Попытка
НовыйДоговор.Записать();
ДоговорСсылка = НовыйДоговор.Ссылка;
Исключение
Сообщить("Не удалось создать договор: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
Таким образом, мы рассмотрели все этапы работы: от простого поиска до массовой обработки данных с созданием новых элементов. Использование запросов с четкими фильтрами по владельцу, организации и виду договора — это залог корректного формирования отчетности в будущем.