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