При переходе с платформы 1С 7.7 на 1С 8.3 программисты часто сталкиваются с архитектурным барьером. В старой версии системы было привычным делом прервать выполнение кода на сервере, выбросить на экран модальное окно с вопросом Вопрос() или вызвать форму выбора справочника Выбрать() прямо внутри цикла загрузки. В современных управляемых формах 1С 8.3 такая логика не только считается «дурным тоном», но и технически невозможна в серверном контексте. Разберем по шагам, как переписать подобную загрузку по современным стандартам.
Проанализируем ситуацию: в 1С 8.3 (особенно в веб-клиенте и тонком клиенте) существует жесткое разделение на клиент и сервер. Серверный код не может открывать окна или взаимодействовать с пользователем. Кроме того, современные интерфейсы стремятся к асинхронности. Если вы запустите «бесконечный» цикл на сервере, который будет ждать ответа пользователя, вы заблокируете ресурсы системы. Поэтому современный стандарт разработки (согласно канонам БСП и платформы 8.3) требует разделения процесса на подготовку данных и их финальную запись.
Вместо того чтобы пытаться создать документ «на лету» во время чтения файла, мы создадим промежуточное звено. Рассмотрим алгоритм: сначала мы считываем данные из внешнего источника (Excel, CSV, XML) и помещаем их в Таблицу значений, которая отображается на управляемой форме обработки.
Это дает нам ряд преимуществ:
Для этого создадим реквизит формы ДанныеЗагрузки с типом ТаблицаЗначений. Добавим в неё колонки: НаименованиеИзФайла, Контрагент (тип СправочникСсылка.Контрагенты), Статус (строка или число для индикации состояния).
После того как данные попали в таблицу на форме, необходимо выполнить серверную процедуру поиска соответствий. Разберем пример кода, который выполняет поиск контрагентов по ИНН или наименованию:
&НаСервере
Процедура СопоставитьДанныеНаСервере()
Для Каждого СтрокаТЗ Из Объект.ДанныеЗагрузки Цикл
// Сначала ищем по ИНН, так как это самый надежный идентификатор
Если ЗначениеЗаполнено(СтрокаТЗ.ИНН) Тогда
НайденныйСсылка = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", СтрокаТЗ.ИНН);
Если Не НайденныйСсылка.Пустая() Тогда
СтрокаТЗ.Контрагент = НайденныйСсылка;
СтрокаТЗ.Статус = "Найден по ИНН";
Продолжить;
КонецЕсли;
КонецЕсли;
// Если по ИНН не нашли, пробуем по наименованию
НайденныйСсылка = Справочники.Контрагенты.НайтиПоНаименованию(СтрокаТЗ.НаименованиеИзФайла, Истина);
Если Не НайденныйСсылка.Пустая() Тогда
СтрокаТЗ.Контрагент = НайденныйСсылка;
СтрокаТЗ.Статус = "Сопоставлено по имени";
Иначе
СтрокаТЗ.Статус = "Контрагент не найден!";
// Здесь мы ничего не открываем, просто помечаем строку для пользователя
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Теперь выясним, как заменить тот самый «Выбор из справочника». Когда процедура валидации завершена, пользователь видит в таблице строки, где колонка Контрагент пуста, а статус горит красным. В управляемых формах нам не нужно писать специальный код для вызова диалога выбора — достаточно того, что у колонки таблицы Контрагент установлен тип СправочникСсылка.Контрагенты.
Пользователь просто нажимает на кнопку выбора («...») в ячейке таблицы, и открывается стандартная форма выбора справочника. Это происходит интерактивно и асинхронно, не прерывая работу программы. После выбора значения пользователем, данные в строке таблицы обновляются.
Важный совет: Чтобы пользователю было удобнее, можно использовать условное оформление формы, чтобы подсвечивать строки с пустым контрагентом красным фоном.
Только когда пользователь проверил все данные и заполнил пустые ячейки (сопоставил всех контрагентов), он нажимает кнопку «Загрузить». В этот момент программа проходит по уже полностью валидной таблице и создает документы без единого вопроса к пользователю.
&НаСервере
Процедура ВыполнитьЗагрузкуНаСервере()
Для Каждого СтрокаТЗ Из Объект.ДанныеЗагрузки Цикл
Если СтрокаТЗ.Контрагент.Пустая() Тогда
// Если пользователь проигнорировал ошибку, пропускаем или выдаем сообщение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не выбран контрагент в строке с наименованием: " + СтрокаТЗ.НаименованиеИзФайла;
Сообщение.Сообщить();
Продолжить;
КонецЕсли;
// Создаем документ
НовыйДок = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДата();
НовыйДок.Контрагент = СтрокаТЗ.Контрагент;
// Заполнение остальных реквизитов...
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
КонецПроцедуры
Если специфика задачи всё же требует задать вопрос пользователю в процессе выполнения какой-то логики на клиенте, проанализируем механизм ОписаниеОповещения. В 1С 8.3 нельзя написать Если Вопрос(...) = КодВозвратаДиалога.Да Тогда. Нужно использовать следующий подход:
&НаКлиенте
Процедура НачатьОбработкуСтроки(ТекДанные)
ПараметрыОповещения = Новый ОписаниеОповещения("ПослеВопросаОКонтрагенте", ЭтотОбъект, ТекДанные);
ТекстВопроса = "Контрагент " + ТекДанные.Наименование + " не найден. Выбрать вручную?";
ПоказатьВопрос(ПараметрыОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВопросаОКонтрагенте(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// Открываем форму выбора
ПараметрыВыбора = Новый Структура("ВыборКонтрагента", Истина);
ОписаниеВыбора = Новый ОписаниеОповещения("ПослеВыбораКонтрагента", ЭтотОбъект, ДополнительныеПараметры);
ОткрытьФорму("Справочник.Контрагенты.ФормаВыбора", ПараметрыВыбора, ЭтотОбъект, , , , ОписаниеВыбора);
КонецЕсли;
КонецПроцедуры
Как мы видим, код становится «разрывным». Каждое действие пользователя требует отдельной процедуры-обработчика. Именно поэтому использование буферной таблицы (как описано в этапе 1) является более предпочтительным, чистым и надежным методом разработки в системе 1С:Предприятие 8.3.
Проанализировав переход с 7.7 на 8.3, можно выделить главное правило: массовая генерация объектов не должна прерываться диалогами. Подготовьте данные, дайте пользователю инструмент для их визуальной проверки и исправления, и только затем запускайте транзакцию создания документов. Это обеспечит стабильность работы системы и удобство для конечного пользователя.