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