Добрый день, коллеги и сочувствующие!
На днях появилась задача - в форме обработки программно заполнять табличную часть данными документа.
На примере коротенькой процедуры я отмечу, с какими подводными камнями столкнулся.
Для простоты задачи я изначально подготовил в форме нужный реквизит с типом ТаблицаЗначений, разместил его на форме, но без колонок.
А далее по кнопке выполняется заполнение таблицы по переданной ссылке.
Но при пересчете числовых значений быстро обнаружилось, что суммы считаются не до 2 знаков после запятой, а гораздо больше.
Провозившись в отладке пару часов, разобрался - все дело в создании числовых реквизитов, у которых описание типов создано на основании массива типов, а не единичного типа "Число".
//<<Дополнение от 03,06,15
А ларчик просто открывался! Описание типов имеет два конструктора - на основании другого описания типов, и на основании типов и квалификаторов.
Так вот, для описанного ниже примера достаточно просто написать
Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл
НоваяКолонка = Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ИмяТаблицы);
МассивРеквизитов.Добавить(НоваяКолонка);
КонецЦикла;
Колонка.ТипЗначения - это описание типов. В случае, если нам нужно другое описание типов (вместо того, что мы получаем из типа значений колонки), можно пойти двумя путями - создать новое описание типов на основе исходного, либо новое описание на основе типов и квалификаторов.
В первом случае можно написать, например так (убираем из исходного описания тип Null):
Новый ОписаниеТипов(Колонка.ТипЗначения,,"Null")
А во втором случае есть два варианта; можно написать, например
Новый ОписаниеТипов("Строка, Число", Новый КвалификаторыЧисла(12,2));
Или
Массив = Новый Массив(2);
Массив.Добавить(Тип("Строка"));
Массив.Добавить(Тип("Число"));
Новый ОписаниеТипов(МассивТипов, Новый КвалификаторыЧисла(12,2));
Тем самым мы явно задаем квалификаторы числа
//>>Конец дополнения
&НаСервере Процедура ЗаполнитьТЗ(ДокЗаказ, ИмяТаблицы) //Очищаем таблицу при передаче пустой ссылки (срабатывает при очистке реквизита ЗаказКлиента в форме) Если Не ЗначениеЗаполнено(ДокЗаказ) Тогда ТЗ_рез = РеквизитФормыВЗначение(ИмяТаблицы); ТЗ_рез.Очистить(); ЗначениеВРеквизитФормы(ТЗ_рез, ИмяТаблицы); Возврат; КонецЕсли; ТЗ_рез = РеквизитФормыВЗначение(ИмяТаблицы); МассивРеквизитов = Новый Массив; //Выполним запрос ТекстЗапроса = "ВЫБРАТЬ | ЗаказКлиентаТовары.Номенклатура, | ЗаказКлиентаТовары.Характеристика, | ЗаказКлиентаТовары.ВариантОбеспечения, | ЗаказКлиентаТовары.КоличествоУпаковок, | ЗаказКлиентаТовары.Упаковка, | ЗаказКлиентаТовары.Цена, | ЗаказКлиентаТовары.ПроцентРучнойСкидки, | ЗаказКлиентаТовары.СуммаРучнойСкидки, | ВЫРАЗИТЬ(ЗаказКлиентаТовары.Сумма КАК ЧИСЛО(15, 2)) КАК Сумма, | ЗаказКлиентаТовары.СтавкаНДС, | ЗаказКлиентаТовары.СуммаНДС, | ЗаказКлиентаТовары.СуммаСНДС, | ЗаказКлиентаТовары.Ссылка, | ЗаказКлиентаТовары.НомерСтроки, | ЗаказКлиентаТовары.ДатаОтгрузки, | ЗаказКлиентаТовары.Назначение, | ЗаказКлиентаТовары.ВидЦены, | ЗаказКлиентаТовары.Количество, | ЗаказКлиентаТовары.ПроцентАвтоматическойСкидки, | ЗаказКлиентаТовары.СуммаАвтоматическойСкидки, | ЗаказКлиентаТовары.ПричинаОтмены, | ЗаказКлиентаТовары.КодСтроки, | ЗаказКлиентаТовары.Отменено, | ЗаказКлиентаТовары.КлючСвязи, | ЗаказКлиентаТовары.Склад, | ЗаказКлиентаТовары.СрокПоставки, | ЗаказКлиентаТовары.Содержание, | ЗаказКлиентаТовары.СтатусУказанияСерий, | ЗаказКлиентаТовары.УказыватьСерии, | ЗаказКлиентаТовары.дПретензияОтПокупателя, | ЗаказКлиентаТовары.РС_НомерПалеты, | ЗаказКлиентаТовары.Серия, | ЗаказКлиентаТовары.НоменклатураНабора, | ИСТИНА КАК БезВозвратнойТары, | ЗаказКлиентаТовары.Сумма КАК СуммаБезВозвратнойТары, | ЗаказКлиентаТовары.СуммаНДС КАК СуммаНДСБезВозвратнойТары, | ЗаказКлиентаТовары.СуммаСНДС КАК СуммаСНДСБезВозвратнойТары, | ЗаказКлиентаТовары.СуммаАвтоматическойСкидки КАК СуммаАвтоматическойСкидкиБезВозвратнойТары, | ЗаказКлиентаТовары.СуммаРучнойСкидки КАК СуммаРучнойСкидкиБезВозвратнойТары, | ЗаказКлиентаТовары.ХарактеристикаНабора |ИЗ | Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары |ГДЕ | ЗаказКлиентаТовары.Ссылка = &Ссылка"; Запрос = Новый Запрос; Запрос.Текст = ТекстЗапроса; Запрос.УстановитьПараметр("Ссылка", ДокЗаказ); //Такой запрос со всеми колонками ТЧ заказа нужен для того, чтобы затем корректно загрузить табличную часть в документ. //В принципе этот пример можно рассматривать с одним единственным реквизитом:) ТЗ_рез = Запрос.Выполнить().Выгрузить(); //Создадим реквизиты ТЗ _РеквизитТЗ = РеквизитФормыВЗначение(ИмяТаблицы); Если _РеквизитТЗ.Колонки.Количество()= 0 Тогда МассивРеквизитов.Очистить(); //Закомментированный кусок - не отработает, и тут есть такой нюанс. //Если создавать реквизиты с описанием типов на основании массива, то даже если у вас с массиве один элемент, квалификаторычисла будут нулевыми //Для того чтобы созданный реквизит (в моем случае числовой) имел заданную точность, его нужно создавать немного-по другому //Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл // МассивТипов = Новый Массив; // МассивТипов.Добавить(Колонка.ТипЗначения); // НоваяКолонка = Новый РеквизитФормы(Колонка.Имя, Новый ОписаниеТипов(МассивТипов), ИмяТаблицы); // МассивРеквизитов.Добавить(НоваяКолонка); //КонецЦикла; Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл //Вторая хитрость. Таблица значений, которую возвращает запрос, по умолчанию имеет плюс ко всем типам тип NULL. В результате опять же массив типов (см.выше). //Мы убираем Null, и на выходе имеем описание типов с нужными квалификаторами (разумеется, если они получены из исходного запроса. //Если создаем реквизит не на основании готовой выборки или таблицы, делаем например так: //ОТ = Новый ОписаниеТипов(Колонка.ТипЗначения,,"Null",,,Новый КвалификаторыДанных(15,2)); ОТ = Новый ОписаниеТипов(Колонка.ТипЗначения,,"Null"); НоваяКолонка = Новый РеквизитФормы(Колонка.Имя, ОТ, ИмяТаблицы); МассивРеквизитов.Добавить(НоваяКолонка); КонецЦикла; ИзменитьРеквизиты(МассивРеквизитов); ЗначениеВРеквизитФормы(ТЗ_рез, ИмяТаблицы); //Создаем элементы на форме для отображения колонок ЭлементТЗ = Элементы[ИмяТаблицы]; Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл НовыйЭлементФормы = Элементы.Добавить(ИмяТаблицы+Колонка.Имя, Тип("ПолеФормы"), ЭлементТЗ); НовыйЭлементФормы.Вид = ВидПоляФормы.ПолеВвода; НовыйЭлементФормы.ПутьКДанным = ИмяТаблицы + "." + Колонка.Имя; КонецЦикла; Иначе ЗначениеВРеквизитФормы(ТЗ_рез, ИмяТаблицы); КонецЕсли; КонецПроцедуры
Вот, собственно, и все. Я убил около 2 часов на то, чтобы понять, как создать реквизит с нужной мне точностью. Надеюсь, кому-нибудь пригодится.