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