Как организовать выбор и сопоставление договора контрагента при загрузке данных в 1С 8.3

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

При разработке обработок загрузки документов из внешних источников (файлов XML, Excel, сторонних систем) в управляемом приложении 1С:Предприятие 8.3 разработчики нередко сталкиваются с ситуацией, когда данные справочников в базах не синхронизированы. Например, контрагент найден по ИНН/КПП, а наименование договора в источнике отличается от наименования в учетной системе или договор вовсе отсутствует.

Попытка приостановить выполнение серверного кода загрузки и напрямую запросить у пользователя выбор договора через методы ПоказатьВводЗначения или ОткрытьФорму приводит к ошибкам компиляции и времени выполнения. Разберем, почему возникает эта проблема и как правильно реализовать выбор подчиненного элемента справочника в соответствии со стандартами разработки платформы 1С.

Причины ошибок при попытке интерактивного ввода на сервере

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

  1. Клиент-серверное разделение и однонаправленность вызовов. В управляемом приложении вызовы процедур строго однонаправлены: клиентская часть может обращаться к серверу, но серверная процедура не может приостановить свое выполнение, вызвать клиента и ожидать ответа пользователя. Конструктор ОписаниеОповещения, глобальные функции ПоказатьВводЗначения и ОткрытьФорму доступны исключительно в контексте &НаКлиенте. Попытка вызвать их на сервере вызывает исключение вида «Процедура или функция с указанным именем не определена».
  2. Ограничения метода ПоказатьВводЗначения. Данная функция предназначена для простого ввода примитивных типов или выбора элементов из плоского списка. Для подчиненного справочника СправочникСсылка.ДоговорыКонтрагентов в нее нельзя штатно передать фильтрацию по владельцу (конкретному контрагенту), из-за чего пользователь увидит общий неотфильтрованный список договоров всех контрагентов базы.

Решение 1: Двухэтапная загрузка с предварительным сопоставлением данных

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

  1. Этап 1 (Серверный анализ): Обработка считывает входной файл (например, XML), ищет объекты по ключевым полям и формирует таблицу несопоставленных элементов (где указан контрагент, исходное строковое наименование договора из файла и вид операции).
  2. Этап 2 (Клиентский интерфейс сопоставления): Список несопоставленных позиций отображается пользователю на форме обработки. Пользователь в удобной табличной части сопоставляет договоры вручную, выбирая существующие или отмечая необходимость создания новых.
  3. Этап 3 (Исполнение загрузки на сервере): Готовая таблица соответствий передается на сервер, после чего все документы создаются, заполняются и проводятся в едином цикле без дополнительных запросов к интерфейсу.

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

Решение 2: Открытие формы выбора договора на клиенте с отбором по владельцу

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

Посмотрим на пример клиентского кода, открывающего форму выбора с фильтром по владельцу:


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

&НаКлиенте
Процедура ПослеВыбораДоговора(ВыбранноеЗначение, ДополнительныеПараметры) Экспорт
    
    Если ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
        // Пользователь выбрал договор из списка
        ПродолжитьЗагрузкуСДоговором(ВыбранноеЗначение);
    Иначе
        // Пользователь закрыл форму выбора или отказался от выбора
        // Здесь можно создать новый договор или пропустить документ
        ОбработатьОтказОтВыбора();
    КонецЕсли;
    
КонецПроцедуры

Обратим внимание: обработчик оповещения обязательно должен быть объявлен с директивой &НаКлиенте и ключевым словом Экспорт.

Решение 3: Автоматическая эвристика поиска для сокращения ручного ввода

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

  1. Проверка количества договоров: Выполняем запрос к базе по владельцу (найденному контрагенту). Если у контрагента заведен ровно один действующий договор (ПометкаУдаления = Ложь), автоматически подставляем его в документ.
  2. Фильтрация по виду договора и организации: Отбираем договоры с подходящим видом (например, СПоставщиком или СПокупателем, определенным по типу загружаемой операции) и указанной организацией документа.
  3. Валюта взаиморасчетов: Учитываем совпадение валюты документа и валюты договора.

Посмотрим на пример серверной функции для поиска подходящего договора:


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

Сохранение соответствий для будущих загрузок

Чтобы избежать повторных вопросов пользователю при следующих регулярных обменах, результаты ручного сопоставления рекомендуется фиксировать. В конфигурации 1С:Бухгалтерия предприятия 3.0 для этого можно использовать механизмы подсистемы сопоставления данных БСП либо создать собственный непериодический независимый регистр сведений, хранящий связку идентификатора/наименования договора из внешней системы и ссылки СправочникСсылка.ДоговорыКонтрагентов в текущей базе.

← На главную