gifts2017

Программное создание реквизита управляемой формы заданной точности

Опубликовал Алексей Леонов (axelerleo) в раздел Программирование - Практика программирования

Пример из практики - программное создание реквизитов на управляемой форме с заданной точностью, а также некоторые комментарии.

Добрый день, коллеги и сочувствующие! 
На днях появилась задача - в форме обработки программно заполнять табличную часть данными документа. 
На примере коротенькой процедуры я отмечу, с какими подводными камнями столкнулся. 
Для простоты задачи я изначально подготовил в форме нужный реквизит с типом ТаблицаЗначений, разместил его на форме, но без колонок. 
А далее по кнопке выполняется заполнение таблицы по переданной ссылке. 
Но при пересчете числовых значений быстро обнаружилось, что суммы считаются не до 2 знаков после запятой, а гораздо больше. 
Провозившись в отладке пару часов, разобрался - все дело в создании числовых реквизитов, у которых описание типов создано на основании массива типов, а не единичного типа "Число". 

 

//<<Дополнение от 03,06,15

А ларчик просто открывался! Описание типов имеет два конструктора - на основании другого описания типов, и на основании типов и квалификаторов.

 

Так вот, для описанного ниже примера достаточно просто написать

		Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл
			НоваяКолонка = Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ИмяТаблицы);
			МассивРеквизитов.Добавить(НоваяКолонка);
		КонецЦикла; 

Колонка.ТипЗначения - это описание типов. В случае, если нам нужно другое описание типов (вместо того, что мы получаем из типа значений колонки), можно пойти двумя путями - создать новое описание типов на основе исходного, либо новое описание на основе типов и квалификаторов.

В первом случае можно написать, например так (убираем из исходного описания тип Null):

Новый ОписаниеТипов(Колонка.ТипЗначения,,"Null")

А во втором случае есть два варианта; можно написать, например 

Новый ОписаниеТипов("Строка, Число", Новый КвалификаторыЧисла(12,2));

Или

 

Массив = Новый Массив(2);
Массив.Добавить(Тип("Строка"));
Массив.Добавить(Тип("Число"));
Новый ОписаниеТипов(МассивТипов, Новый КвалификаторыЧисла(12,2));


Тем самым мы явно задаем квалификаторы числа

//>>Конец дополнения

&НаСервере
Процедура ЗаполнитьТЗ(ДокЗаказ, ИмяТаблицы)
    
//Очищаем таблицу при передаче пустой ссылки (срабатывает при очистке реквизита ЗаказКлиента в форме)
    Если Не ЗначениеЗаполнено(ДокЗаказ) Тогда
        ТЗ_рез = РеквизитФормыВЗначение(ИмяТаблицы);
        ТЗ_рез.Очистить();
        ЗначениеВРеквизитФормы(ТЗ_рез, ИмяТаблицы);
        Возврат;
    КонецЕсли;


    ТЗ_рез = РеквизитФормыВЗначение(ИмяТаблицы);
    
    МассивРеквизитов = Новый Массив;
    
    //Выполним запрос
    ТекстЗапроса = "ВЫБРАТЬ
    |    ЗаказКлиентаТовары.Номенклатура,
    |    ЗаказКлиентаТовары.Характеристика,
    |    ЗаказКлиентаТовары.ВариантОбеспечения,
    |    ЗаказКлиентаТовары.КоличествоУпаковок,
    |    ЗаказКлиентаТовары.Упаковка,
    |    ЗаказКлиентаТовары.Цена,
    |    ЗаказКлиентаТовары.ПроцентРучнойСкидки,
    |    ЗаказКлиентаТовары.СуммаРучнойСкидки,
    |    ВЫРАЗИТЬ(ЗаказКлиентаТовары.Сумма КАК ЧИСЛО(15, 2)) КАК Сумма,
    |    ЗаказКлиентаТовары.СтавкаНДС,
    |    ЗаказКлиентаТовары.СуммаНДС,
    |    ЗаказКлиентаТовары.СуммаСНДС,
    |    ЗаказКлиентаТовары.Ссылка,
    |    ЗаказКлиентаТовары.НомерСтроки,
    |    ЗаказКлиентаТовары.ДатаОтгрузки,
    |    ЗаказКлиентаТовары.Назначение,
    |    ЗаказКлиентаТовары.ВидЦены,
    |    ЗаказКлиентаТовары.Количество,
    |    ЗаказКлиентаТовары.ПроцентАвтоматическойСкидки,
    |    ЗаказКлиентаТовары.СуммаАвтоматическойСкидки,
    |    ЗаказКлиентаТовары.ПричинаОтмены,
    |    ЗаказКлиентаТовары.КодСтроки,
    |    ЗаказКлиентаТовары.Отменено,
    |    ЗаказКлиентаТовары.КлючСвязи,
    |    ЗаказКлиентаТовары.Склад,
    |    ЗаказКлиентаТовары.СрокПоставки,
    |    ЗаказКлиентаТовары.Содержание,
    |    ЗаказКлиентаТовары.СтатусУказанияСерий,
    |    ЗаказКлиентаТовары.УказыватьСерии,
    |    ЗаказКлиентаТовары.дПретензияОтПокупателя,
    |    ЗаказКлиентаТовары.РС_НомерПалеты,
    |    ЗаказКлиентаТовары.Серия,
    |    ЗаказКлиентаТовары.НоменклатураНабора,
    |    ИСТИНА КАК БезВозвратнойТары,
    |    ЗаказКлиентаТовары.Сумма КАК СуммаБезВозвратнойТары,
    |    ЗаказКлиентаТовары.СуммаНДС КАК СуммаНДСБезВозвратнойТары,
    |    ЗаказКлиентаТовары.СуммаСНДС КАК СуммаСНДСБезВозвратнойТары,
    |    ЗаказКлиентаТовары.СуммаАвтоматическойСкидки КАК СуммаАвтоматическойСкидкиБезВозвратнойТары,
    |    ЗаказКлиентаТовары.СуммаРучнойСкидки КАК СуммаРучнойСкидкиБезВозвратнойТары,
    |    ЗаказКлиентаТовары.ХарактеристикаНабора
    |ИЗ
    |    Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
    |ГДЕ
    |    ЗаказКлиентаТовары.Ссылка = &Ссылка";
    Запрос = Новый Запрос;
    Запрос.Текст = ТекстЗапроса;
    Запрос.УстановитьПараметр("Ссылка", ДокЗаказ);
//Такой запрос со всеми колонками ТЧ заказа нужен для того, чтобы затем корректно загрузить табличную часть в документ.
//В принципе этот пример можно рассматривать с одним единственным реквизитом:) 
ТЗ_рез = Запрос.Выполнить().Выгрузить();
    
    //Создадим реквизиты ТЗ
    _РеквизитТЗ = РеквизитФормыВЗначение(ИмяТаблицы);
    Если _РеквизитТЗ.Колонки.Количество()= 0 Тогда
        МассивРеквизитов.Очистить();

//Закомментированный кусок - не отработает, и тут есть такой нюанс.
//Если создавать реквизиты с описанием типов на основании массива, то даже если у вас с массиве один элемент, квалификаторычисла будут нулевыми
//Для того чтобы созданный реквизит (в моем случае числовой) имел заданную точность, его нужно создавать немного-по другому
        //Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл
        // МассивТипов = Новый Массив;
        // МассивТипов.Добавить(Колонка.ТипЗначения);
        // НоваяКолонка = Новый РеквизитФормы(Колонка.Имя, Новый ОписаниеТипов(МассивТипов), ИмяТаблицы);
        // МассивРеквизитов.Добавить(НоваяКолонка);
        //КонецЦикла; 

        
        Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл
 //Вторая хитрость. Таблица значений, которую возвращает запрос, по умолчанию имеет плюс ко всем типам тип NULL. В результате опять же массив типов (см.выше).
 //Мы убираем Null, и на выходе имеем описание типов с нужными квалификаторами (разумеется, если они получены из исходного запроса.
 //Если создаем реквизит не на основании готовой выборки или таблицы, делаем например так:
 //ОТ = Новый ОписаниеТипов(Колонка.ТипЗначения,,"Null",,,Новый КвалификаторыДанных(15,2));

            ОТ = Новый ОписаниеТипов(Колонка.ТипЗначения,,"Null");
            НоваяКолонка = Новый РеквизитФормы(Колонка.Имя, ОТ, ИмяТаблицы);
            МассивРеквизитов.Добавить(НоваяКолонка);
        КонецЦикла;      
        ИзменитьРеквизиты(МассивРеквизитов);  
        ЗначениеВРеквизитФормы(ТЗ_рез, ИмяТаблицы);
        
        //Создаем элементы на форме для отображения колонок
        ЭлементТЗ = Элементы[ИмяТаблицы];
        Для Каждого Колонка ИЗ ТЗ_рез.Колонки Цикл
            НовыйЭлементФормы = Элементы.Добавить(ИмяТаблицы+Колонка.Имя, Тип("ПолеФормы"), ЭлементТЗ);
            НовыйЭлементФормы.Вид = ВидПоляФормы.ПолеВвода;
            НовыйЭлементФормы.ПутьКДанным = ИмяТаблицы + "." + Колонка.Имя;
        КонецЦикла;
    Иначе
        ЗначениеВРеквизитФормы(ТЗ_рез, ИмяТаблицы);
    КонецЕсли;

КонецПроцедуры



Вот, собственно, и все. Я убил около 2 часов на то, чтобы понять, как создать реквизит с нужной мне точностью. Надеюсь, кому-нибудь пригодится.


См. также

Подписаться Добавить вознаграждение
Комментарии
1. Андрей Акулов (DrAku1a) 04.06.15 03:43
Примеры работы с описанием типов есть в справке 1С.
Полезного в статье - только первый приведённый блок кода.
Но всё-же спасибо, что делитесь опытом обхождения граблей - иной раз, две строчки кода бывают важнее, чем сотни.
2. Петр Лунегов (pvlunegov) 09.06.15 10:37
(1) DrAku1a,
Я бы не стал так категорично к автору относится.
Я скажу - МОЛОДЕЦ!
Я занимаюсь таким же как ты делом.
Если успешно решил определенную проблему, делаю статью и выкладываю на Инфостарте.
Сначала навалятся всякие гении 1с и будут кидать тухлыми помидорами, улюлюкать и кричать отстой.
Подожди немного, позже подключатся нормальные люди, которым твоя статья поможет, они скажут спасибо или плюс поставят.

Короче, уважение за хорошую статью тебе, Алексей!