ОписаниеТипов, ИзменитьРеквизиты и ОграничениеТипа: управляем типом реквизита из кода 1С
Содержание
Программно тип реквизита в 1С задают объектом ОписаниеТипов: Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(100)). Этот объект передают в Новый РеквизитФормы(...) и ИзменитьРеквизиты(), в колонку таблицы значений, в свойство ТипЗначения плана видов характеристик или в ОграничениеТипа поля формы. Тип реквизита объекта метаданных (справочника, документа) из кода в режиме Предприятия не меняется: это делают в Конфигураторе.
Всё ниже относится к платформе 8.3 и управляемым формам. Код одинаково работает в любой конфигурации: БП 3.0, ЗУП 3.1, УТ 11 или самописной. Имена справочников в примерах условные, подставьте свои.
Чем задают тип в 1С: ОписаниеТипов и квалификаторы
Тип в языке 1С — это значение Тип, например Тип("СправочникСсылка.Контрагенты"). Но реквизиту нужен не один тип, а описание: какие типы допустимы и с какими ограничениями. За это отвечает ОписаниеТипов.
Основная форма конструктора: Новый ОписаниеТипов(Типы, КвалификаторыЧисла, КвалификаторыСтроки, КвалификаторыДаты). Типы передают строкой через запятую или массивом значений Тип. Пропущенные параметры оставляют пустыми между запятыми.
// Строка до 150 символов, переменной длины
ТипСтрока = Новый ОписаниеТипов("Строка", ,
Новый КвалификаторыСтроки(150, ДопустимаяДлина.Переменная));
// Число 15.2, только неотрицательное
ТипСумма = Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(15, 2, ДопустимыйЗнак.Неотрицательный));
// Дата без времени
ТипДата = Новый ОписаниеТипов("Дата", , ,
Новый КвалификаторыДаты(ЧастиДаты.Дата));
// Ссылка на справочник
ТипКонтрагент = Новый ОписаниеТипов("СправочникСсылка.Контрагенты");
// Булево
ТипФлаг = Новый ОписаниеТипов("Булево");
Квалификаторы повторяют то, что в Конфигураторе задают в свойстве «Тип»:
| Квалификатор | Параметры | Пример |
|---|---|---|
КвалификаторыСтроки | длина, ДопустимаяДлина | (50) — строка до 50 символов |
КвалификаторыЧисла | разрядность, дробная часть, ДопустимыйЗнак | (10, 3) — до 9 999 999,999 |
КвалификаторыДаты | ЧастиДаты.Дата, .Время, .ДатаВремя | только дата без времени |
Проверим пример из таблицы: разрядность 10 и дробная часть 3 дают 7 знаков до запятой. Максимум — 9 999 999,999.
Строка с длиной 0 — это неограниченная строка. Такой реквизит нельзя использовать в отборах и сравнениях запроса без ПОДСТРОКА, поэтому для полей, по которым ищут, ставьте конкретную длину.
Как установить тип реквизита формы программно
Самый частый сценарий — добавить на форму реквизит, которого нет в Конфигураторе. Например, в расширении или в форме, где набор полей зависит от настроек. Реквизит создают на сервере методом формы ИзменитьРеквизиты(), тип передают вторым параметром РеквизитФормы.
Шаг 1. Создать реквизит с нужным типом
&НаСервере
Процедура ДобавитьКомментарийСклада()
ТипКомментария = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(500));
Добавляемые = Новый Массив;
Добавляемые.Добавить(Новый РеквизитФормы("КомментарийСклада",
ТипКомментария, , "Комментарий для склада"));
ИзменитьРеквизиты(Добавляемые);
КонецПроцедуры
Параметры РеквизитФормы: имя, описание типов, путь (пусто — реквизит верхнего уровня), заголовок. Вызывать удобно из ПриСозданииНаСервере.
Шаг 2. Вывести реквизит на форму
Реквизит без элемента пользователь не увидит. Добавьте поле и свяжите его через ПутьКДанным:
Поле = Элементы.Добавить("КомментарийСклада", Тип("ПолеФормы"));
Поле.Вид = ВидПоляФормы.ПолеВвода;
Поле.ПутьКДанным = "КомментарийСклада";
Шаг 3. Обращаться к значению по имени
Реквизит появился во время выполнения, поэтому в коде модуля к нему обращаются через квадратные скобки: ЭтотОбъект["КомментарийСклада"]. Прямое имя КомментарийСклада при компиляции модуля ещё неизвестно.
Реквизиты колонок и табличных частей формы
Чтобы задать тип колонки у реквизита-таблицы, третьим параметром укажите путь к таблице:
Добавляемые.Добавить(Новый РеквизитФормы("Скидка",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(5, 2)), "Товары"));
Для таблицы значений в памяти (не на форме) тип колонки задают при добавлении: ТЗ.Колонки.Добавить("Сумма", ТипСумма, "Сумма, руб."). Без типа колонка примет любое значение, и при выводе на форму или в запрос с такой колонкой начнутся проблемы.
Как сменить тип уже созданного реквизита формы
Свойство типа у существующего реквизита формы не перезаписывается. Тип меняют пересозданием: удалить реквизит и добавить с тем же именем и новым типом.
&НаСервере
Процедура СменитьТипРеквизитаФормы(ИмяРеквизита, НовыйТип)
Удаляемые = Новый Массив;
Удаляемые.Добавить(ИмяРеквизита);
ИзменитьРеквизиты(, Удаляемые);
Добавляемые = Новый Массив;
Добавляемые.Добавить(Новый РеквизитФормы(ИмяРеквизита, НовыйТип));
ИзменитьРеквизиты(Добавляемые);
КонецПроцедуры
Удалить так можно только реквизит, добавленный программно. Реквизит, созданный в Конфигураторе, ИзменитьРеквизиты() не удалит. Для него есть другой путь: в Конфигураторе дать составной тип, а в коде сужать его через ОграничениеТипа (раздел про составной тип ниже). Значение реквизита при пересоздании теряется, сохраните его заранее.
Реквизиты, тип которых хранится в данных: планы видов характеристик
Бывает, что тип нужно менять без доработки конфигурации вообще. Для этого в 1С есть планы видов характеристик (ПВХ). Каждый элемент ПВХ хранит свой тип в стандартном реквизите ТипЗначения. На этом устроены дополнительные реквизиты и сведения в типовых конфигурациях, виды субконто в плане счетов, свойства номенклатуры.
Создать вид характеристики с нужным типом:
Вид = ПланыВидовХарактеристик.ВидыХарактеристик.СоздатьЭлемент();
Вид.Наименование = "Срок гарантии, мес.";
Вид.ТипЗначения = Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(3, 0, ДопустимыйЗнак.Неотрицательный));
Вид.Записать();
Три правила, без которых код работает не так, как ждёте:
- 📌 В
ТипЗначенияможно указывать только типы, которые входят в «Тип значения характеристик» самого ПВХ. Этот общий список задают в Конфигураторе. - 📌 Смена
ТипЗначенияу вида, по которому уже есть значения, не конвертирует старые данные. Записи регистра сведений или табличной части останутся со старым типом. Их переносят отдельной обработкой. - 📌 Чтобы поле значения на форме подстраивалось под вид, у реквизита в Конфигураторе заполняют свойство «Связь по типу». Программно то же делают через
Элементы.Значение.ОграничениеТипа = Вид.ТипЗначения.
В типовых конфигурациях на БСП дополнительные реквизиты создают не голым СоздатьЭлемент(), а через стандартную форму в разделе НСИ и администрирование → Общие настройки → Дополнительные реквизиты и сведения (в БП 3.0 — Администрирование → Общие настройки). Там при записи заполняются наборы свойств и служебные поля. Код в обход формы легко оставит «висящий» реквизит, которого нет ни в одном наборе.
Тип полей динамического списка
У динамического списка типы колонок задаёт не программист, а текст запроса. Поэтому «установить тип реквизита » списка — значит правильно написать запрос.
Сузить составное поле через ВЫРАЗИТЬ
Если поле составного типа, а в списке нужен только один вариант, приведите его в запросе:
Список.ПроизвольныйЗапрос = Истина;
Список.ТекстЗапроса =
"ВЫБРАТЬ
| Платеж.Ссылка,
| Платеж.Дата,
| ВЫРАЗИТЬ(Платеж.Получатель КАК Справочник.Контрагенты) КАК Получатель
|ИЗ
| Документ.ПлатежныйДокумент КАК Платеж
|ГДЕ
| Платеж.Получатель ССЫЛКА Справочник.Контрагенты";
Список.ОсновнаяТаблица = "Документ.ПлатежныйДокумент";
После ВЫРАЗИТЬ колонка получает один тип, и через точку становятся доступны реквизиты контрагента. Условие ССЫЛКА отбирает строки нужного типа. Без него строки с другим типом покажут пустое значение.
Создать динамический список программно
Динамический список сам может быть реквизитом формы, созданным из кода. Тип реквизита — ДинамическийСписок:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Добавляемые = Новый Массив;
Добавляемые.Добавить(Новый РеквизитФормы("СписокДоговоров",
Новый ОписаниеТипов("ДинамическийСписок")));
ИзменитьРеквизиты(Добавляемые);
СписокДоговоров = ЭтотОбъект["СписокДоговоров"];
СписокДоговоров.ПроизвольныйЗапрос = Истина;
СписокДоговоров.ОсновнаяТаблица = "Справочник.ДоговорыКонтрагентов";
СписокДоговоров.ТекстЗапроса =
"ВЫБРАТЬ
| Договоры.Ссылка,
| Договоры.Наименование
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК Договоры";
Таблица = Элементы.Добавить("ТаблицаДоговоров", Тип("ТаблицаФормы"));
Таблица.ПутьКДанным = "СписокДоговоров";
Колонка = Элементы.Добавить("ТаблицаДоговоровНаименование", Тип("ПолеФормы"), Таблица);
Колонка.Вид = ВидПоляФормы.ПолеВвода;
Колонка.ПутьКДанным = "СписокДоговоров.Наименование";
КонецПроцедуры
Сначала заполняют ОсновнаяТаблица и текст запроса, потом выводят колонки. Колонку можно привязать только к полю, которое есть в запросе.
Составной тип реквизита: собрать, ограничить, задать конкретный
Составной тип — это ОписаниеТипов с несколькими типами. Собрать его можно тремя способами:
// 1. Строкой
ТипПолучателя = Новый ОписаниеТипов(
"СправочникСсылка.Контрагенты, СправочникСсылка.ФизическиеЛица");
// 2. Массивом типов — удобно, когда список собирается в цикле
Типы = Новый Массив;
Типы.Добавить(Тип("СправочникСсылка.Контрагенты"));
Типы.Добавить(Тип("СправочникСсылка.ФизическиеЛица"));
ТипПолучателя = Новый ОписаниеТипов(Типы);
// 3. От существующего описания: добавить или убрать типы
ТипСоСтрокой = Новый ОписаниеТипов(ТипПолучателя, "Строка");
ТипБезСтроки = Новый ОписаниеТипов(ТипСоСтрокой, , "Строка");
Третья форма конструктора: исходное описание, добавляемые типы, вычитаемые типы. Ею удобно расширять тип из метаданных: Новый ОписаниеТипов(Метаданные.Документы.ПлатежныйДокумент.Реквизиты.Получатель.Тип, "Строка").
Ограничить выбор типа на форме
Реквизит в Конфигураторе составной, а в конкретной ситуации пользователь должен выбирать только контрагентов. Сужают тип у поля формы:
Элементы.Получатель.ОграничениеТипа = Новый ОписаниеТипов("СправочникСсылка.Контрагенты");
Ограничение работает только в пределах типа реквизита. Тип, которого нет в описании реквизита, через ОграничениеТипа не добавить.
Задать конкретный тип значению
Иногда нужно не ограничить выбор, а сразу «переключить» пустое значение на нужный тип. Тогда кнопка выбора откроет форму именно этого справочника:
Объект.Получатель = Справочники.ФизическиеЛица.ПустаяСсылка();
Тот же результат даёт ПривестиЗначение, когда имя типа известно только во время выполнения:
ОписаниеНужногоТипа = Новый ОписаниеТипов("СправочникСсылка." + ИмяСправочника);
Объект.Получатель = ОписаниеНужногоТипа.ПривестиЗначение(Неопределено);
ПривестиЗначение возвращает значение по умолчанию для первого типа описания. Для ссылки это пустая ссылка нужного справочника.
Тип реквизита справочника или документа: что можно поменять из кода
Тип реквизита объекта конфигурации из кода можно только прочитать. Коллекция Метаданные в режиме Предприятия доступна лишь на чтение:
ТипАртикула = Метаданные.Справочники.Номенклатура.Реквизиты.Артикул.Тип;
Для Каждого ТекТип Из ТипАртикула.Типы() Цикл
Сообщить(ТекТип);
КонецЦикла;
Изменить тип реквизита справочника или документа можно тремя путями:
| Способ | Когда подходит | Риски |
|---|---|---|
| Конфигуратор: свойство «Тип» реквизита | разовая правка своей конфигурации | в типовой нужно включить возможность изменения, это усложняет обновления |
| Новый реквизит в расширении | типовая на поддержке, нужен реквизит другого типа | старый реквизит остаётся, данные переносят обработкой |
Выгрузка конфигурации в XML и правка <Type> | массовая правка, сборка в конвейере | ошибка в XML не даст загрузить конфигурацию |
Пакетный вариант с командной строкой Конфигуратора:
"C:\Program Files\1cv8\8.3.24.1691\bin\1cv8.exe" DESIGNER /F"D:\Bases\Test" /DumpConfigToFiles "D:\cfg"
rem ...правка D:\cfg\Catalogs\Номенклатура.xml...
"C:\Program Files\1cv8\8.3.24.1691\bin\1cv8.exe" DESIGNER /F"D:\Bases\Test" /LoadConfigFromFiles "D:\cfg" /UpdateDBCfg
Номер версии в пути подставьте свой, его видно в папке C:\Program Files\1cv8\.
Смена типа реквизита с данными — реструктуризация базы. Значения, которые не приводятся к новому типу, станут пустыми. Перед изменением структуры сделайте резервную копию базы. Для обновления структуры нужен монопольный доступ, поэтому пользователей придётся отключить.
Проверка типа и ошибки при его установке
Перед записью значения в реквизит полезно проверить, подходит ли тип. Для этого есть ТипЗнч() и метод СодержитТип():
Функция ТипДопустим(Значение, ОписаниеТипаРеквизита)
Возврат ОписаниеТипаРеквизита.СодержитТип(ТипЗнч(Значение));
КонецФункции
Если имя типа собирается из строки, проверьте, что объект есть в конфигурации. Иначе Тип() вызовет исключение:
Если Метаданные.Справочники.Найти(ИмяСправочника) = Неопределено Тогда
ВызватьИсключение СтрШаблон("Справочник %1 не найден в конфигурации", ИмяСправочника);
КонецЕсли;
НужныйТип = Тип("СправочникСсылка." + ИмяСправочника);
Отдельная ловушка — тихое приведение. Присвоение значения реквизиту объекта или формы приводит его к типу реквизита без ошибки. Строку из 200 символов в реквизит длиной 100 платформа обрежет. Ссылку на другой справочник в реквизит с одним типом — заменит пустым значением. Поэтому проверка СодержитТип() перед записью ловит то, что иначе всплывёт через месяц в отчётах.