С версии платформы 8.3.11.2867 стало возможным с помощью расширений добавлять к прикладному решению собственные структуры для хранения данных, в том числе табличные части и реквизиты табличных частей. И это замечательно. Однако не всегда конфигурация работает на старшей версии платформы и в нужном режиме совместимости. Кроме того, при добавлении в расширение объектов хранения данных возможны неочевидные проблемы при обновлении (см., например, публикацию 1039552). Поэтому в ряде случаев представляется разумным использовать совместно с расширением механизм дополнительных реквизитов.
Пример выполнен в конфигурации "1С:Документооборот КОРП 2.1" (далее ДО), однако подход применим к любой конфигурации на управляемых формах с БСП и режимом совместимости, допускающим использование расширений.
Постановка задачи
В конфигурации ДО необходимо создать вид внутреннего документа Премия, с табличной частью позволяющей учитывать премии сотрудников подразделения. При выборе сотрудника в строке табличной части должна подставляться его должность. Реквизит Должность должен быть недоступен для изменения. При изменении в строке ТЧ суммы премии должна изменяться сумма документа – реквизит Итого распределено. Конфигурация на полной поддержке, включать возможность изменения нельзя.
Решение
Создаем вид внутреннего документа – Премия (НСИ / Виды документов / Создать). Устанавливаем флаг Учитывать сумму документа. Остальные настройки – по желанию. (Напомню, что внутренний документ в ДО – это справочник).
Добавляем дополнительные реквизиты для документа Премия (Настройка и администрирование / Дополнительные реквизиты). Каждый доп. реквизит – ячейка эмулируемой табличной части. Предположим для примера, что в подразделении не более трех сотрудников, т.е. в таб. части должно быть три строки.
Итак, добавляем три новых доп. реквизита Сотрудник1 – Соотрудник3:
Обратите внимание, свойства Виден, Доступен и др. заполнять следует только в том случае, если мы не собираемся их изменять программно. Ручные настройки перекрывают программные. В текущей задаче свойства доп. реквизитов заполнять не следует. Исключение – доп. реквизит Фактическая численность, у которого можно установить флаг Заполнять обязательно.
Добавляем три доп. реквизита Должность1 – Должность3 (тип Должность):
Добавляем три доп. реквизита Сумма1 – Сумма3 (тип Число 10, 2):
Аналогично добавляем три доп. реквизита Основание1 – Основание3 (тип Строка).
И добавляем реквизиты шапки: Итого распределено (тип Число 10, 2) и Фактическая численность (тип Число 2,0; Заполнять обязательно).
В результате получаем 14 доп. реквизитов документа Премия, из них два – реквизиты шапки и 12 – реквизиты собственно таблицы:
Далее нужно настроить внешний вид документа Премия. Создаем новый документ вида Премия и переходим на вкладку Свойства, которая будет выглядеть примерно так:
Идем в меню Еще / Настройки / Изменить форму и настраиваем.
У группы Премия устанавливаем горизонтальную группировку.
В группе Премия создаем четыре группы:
— Сотрудник (Отображение – Слабое выделение);
— Занимаемая должность (Отображение – Сильное выделение)
— Сумма премии (Отображение – Сильное выделение)
— Основание (Отображение – Сильное выделение)
У всех групп группировка вертикальная, флаг Отображать заголовок установлен.
Перетаскиваем поля доп. реквизитов в соответствующие группы. В результате форма настройки будет выглядеть так:
У всех полей доп. реквизитов устанавливаем Положение заголовка – Нет.
Настраиваем шапку. В группе Свойства создаем группу Шапка (Отображение – Нет, Группировка – Вертикальная, Отображать заголовок – Нет).
В группе Шапка создаем две группы: Группа подразделение и Группа сумма и численность. У обеих групп Отображение – Нет, Группировка – Горизонтальная, Отображать заголовок – Нет.
В группу Группа подразделение перетаскиваем из группы Реквизиты / Группа элемента / ГруппаПраво / Реквизиты реквизит (стандартный, не доп.) Подразделение и, выделив этот реквизит, добавляем кнопкой Добавить поля реквизит Руководитель.
В группу Группа сумма и численность перетаскиваем из той же группы Реквизиты / Группа элемента / ГруппаПраво / Реквизиты группу Группа сумма и наш доп. реквизит Фактическая численность. У реквизита Сумма устанавливаем заголовок Премиальный фонд (сумма).
Доп. реквизит Итого распределено перемещаем в группу Шапка.
В результате форма настройки будет выглядеть так:
А вкладка Свойства документа Премия так:
Далее открываем конфигуратор и добавляем расширение (Конфигурация / Расширения конфигурации / Добавить):
Добавляем в расширение форму элемента справочника ВнутренниеДокументы и План видов характеристик ДополнительныеРеквизитыИСведения (нужен для установки типа реквизита формы).
В расширении добавляем реквизиты формы:
— ЭтоПремия – тип Булево;
— КоличествоСтрокВТаблицеПремия – тип Число 3,0;
— ИтогоСумма – тип Число 10,2.
— СвойствоИтогоРаспределено – тип ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения.
В принципе, можно обойтись без реквизитов формы, однако тогда форма будет работать медленнее.
Код модуля формы элемента справочника ВнутренниеДокументы в расширении представлен ниже:
// Добавлены реквизиты формы(для документа вида Премия):
// ЭтоПремия - Булево
// ИтогоСумма - Число
// КоличествоСтрокВТаблицеПремия - Число
// СвойствоИтогоРаспределено - ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения
#Область ОбработчикиСобытийФормы
&НаСервере
Процедура Премия_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
Если Объект.ВидДокумента = Справочники.ВидыВнутреннихДокументов.НайтиПоНаименованию("Премия") Тогда
ЭтоПремия = Истина;
///////////////////////////////////
КоличествоСтрокВТаблицеПремия = 3;
///////////////////////////////////
СвойствоИтогоРаспределено = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Итого распределено (Премия)");
ОбработатьУстановкуДействияДляДопреквизитов_Премия(Отказ, СтандартнаяОбработка, Неопределено);
Иначе
ЭтоПремия = Ложь;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура Премия_ПриОткрытииПосле(Отказ)
Если ЭтоПремия Тогда
Элементы.Подразделение.АвтоОтметкаНезаполненного = Истина;
УстановитьСвойстваПолей_Премия();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура Премия_ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты)
Если ЭтоПремия Тогда
Если НЕ ЗначениеЗаполнено(Объект.Подразделение) Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
НСтр("ru = 'Поле ""Подразделение"" не заполнено'"), ,
"Подразделение", "Объект");
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура Премия_ПослеЗаписи(ПараметрыЗаписи)
УстановитьСвойстваПолей_Премия();
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиСобытийЭлементовТаблицыФормыПремияНазначаемые
&НаКлиенте
Процедура СуммаПриИзменении_Премия()
ИтогоСумма = 0;
Для Сч=1 По КоличествоСтрокВТаблицеПремия Цикл
СуммаТекущая = НайтиДопреквизитВФорме("Сумма"+СокрЛП(Сч));
Если СуммаТекущая.Видимость Тогда
ИтогоСумма = ИтогоСумма + Число(СокрЛП(СуммаТекущая.ТекстРедактирования));
КонецЕсли;
КонецЦикла;
УстановитьЗначениеДопРеквизитаИтогоРаспределено();
УстановитьСвойстваПолей_Премия();
КонецПроцедуры
&НаКлиенте
Процедура СотрудникПриИзменении()
ЗначениеДопРеквизитаСотрудник = Вычислить("ЭтаФорма." + ТекущийЭлемент.Имя);
Должность = РаботаСПользователями.ПолучитьДолжность(ЗначениеДопРеквизитаСотрудник);
НаименованиеДопреквизитаСотрудник = ПолучитьНаименованиеДопреквизитаПоИмени(ТекущийЭлемент.Имя);
НомерСтрокиТаблицы = СтрЗаменить(НаименованиеДопреквизитаСотрудник,"Сотрудник","");
НаименованиеДопреквизитаДолжность = "Должность" + НомерСтрокиТаблицы + " (Премия)";
УстановитьЗначениеДопРеквизитаДолжность(НаименованиеДопреквизитаДолжность, Должность);
УстановитьСвойстваПолей_Премия();
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
&НаСервере
Процедура УстановитьДействияДляДопреквизита(НаименованиеДопРеквизита, ДействиеСтрока, ПроцедураСтрока)
СтруктураПоиска = Новый Структура("Наименование", НаименованиеДопРеквизита);
ИмяДопРеквизита = ЭтаФорма.Свойства_ОписаниеДополнительныхРеквизитов.НайтиСтроки(СтруктураПоиска)[0].ИмяРеквизитаЗначение;
ДопРеквизит = Элементы[ИмяДопРеквизита];
ДопРеквизит.УстановитьДействие(ДействиеСтрока, ПроцедураСтрока);
КонецПроцедуры
// Параметры:
// НаименованиеДопРеквизита - Строка
// Возвращаемое значение:
// ПолеФормы - искомый допреквизит типа ПолеФормы
&НаКлиенте
Функция НайтиДопреквизитВФорме(НаименованиеДопРеквизита)
СтруктураПоиска = Новый Структура("Наименование", НаименованиеДопРеквизита);
МассивСтрок = ЭтаФорма.Свойства_ОписаниеДополнительныхРеквизитов.НайтиСтроки(СтруктураПоиска);
Если МассивСтрок.Количество() = 0 Тогда
Возврат Неопределено;
Иначе
ИмяДопРеквизита = МассивСтрок[0].ИмяРеквизитаЗначение;
ДопРеквизит = Элементы[ИмяДопРеквизита];
Возврат ДопРеквизит;
КонецЕсли;
КонецФункции
&НаСервере
Процедура ОбработатьУстановкуДействияДляДопреквизитов_Премия(Отказ, СтандартнаяОбработка, ДополнительныеПараметры)
Для Сч=1 По КоличествоСтрокВТаблицеПремия Цикл
УстановитьДействияДляДопреквизита("Сумма" + СокрЛП(Сч), "ПриИзменении", "СуммаПриИзменении_Премия");
УстановитьДействияДляДопреквизита("Сотрудник" + СокрЛП(Сч), "ПриИзменении", "СотрудникПриИзменении");
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура УстановитьСвойстваПолей_Премия()
УстановитьТолькоПросмотрДляПоля("Итого распределено");
УстановитьТолькоПросмотрДляПолейДолжность();
УстановитьКнопкаОткрытияЛожьДляПолейДолжность();
КонецПроцедуры
// Возвращает наименование доп. реквизита
// Параметры:
// ИмяДопреквизита - Строка. Например, ДополнительныйРеквизитЗначение_71A6C86Dx0E4Ex11E8x873Dx0022155C4930_71A6C875x0E4Ex11E8x873Dx0022155C4930
// Возвращаемое значение:
// НаименованиеДопреквизита - Строка. Например, Сотрудник1
//
&НаКлиенте
Функция ПолучитьНаименованиеДопреквизитаПоИмени(ИмяДопреквизита)
СтруктураПоиска = Новый Структура("ИмяРеквизитаЗначение", ИмяДопреквизита);
МассивСтрок = ЭтаФорма.Свойства_ОписаниеДополнительныхРеквизитов.НайтиСтроки(СтруктураПоиска);
Если МассивСтрок.Количество()=0 Тогда
Возврат Неопределено;
Иначе
НаименованиеДопреквизита = МассивСтрок[0].Наименование;
Возврат НаименованиеДопреквизита;
КонецЕсли;
КонецФункции
&НаСервере
Процедура УстановитьЗначениеДопРеквизитаИтогоРаспределено()
УправлениеСвойствами.ПеренестиЗначенияИзРеквизитовФормыВОбъект(ЭтаФорма, Объект);
НашлиСтроку = Ложь;
Если Объект.ДополнительныеРеквизиты.Количество() = 0 Тогда
НоваяСтрока = Объект.ДополнительныеРеквизиты.Добавить();
НоваяСтрока.Свойство = СвойствоИтогоРаспределено;
НоваяСтрока.Значение = ИтогоСумма;
Иначе
Для каждого Строка Из Объект.ДополнительныеРеквизиты Цикл
Если Строка.Свойство.Ссылка = СвойствоИтогоРаспределено Тогда
Строка.Значение = ИтогоСумма;
НашлиСтроку = Истина;
КонецЕсли;
КонецЦикла;
Если НЕ НашлиСтроку Тогда
НоваяСтрока = Объект.ДополнительныеРеквизиты.Добавить();
НоваяСтрока.Свойство = СвойствоИтогоРаспределено;
НоваяСтрока.Значение = ИтогоСумма;
КонецЕсли;
КонецЕсли;
УправлениеСвойствами.ЗаполнитьДополнительныеРеквизитыВФорме(ЭтаФорма, Объект);
ОбработатьУстановкуДействияДляДопреквизитов_Премия(Неопределено, Неопределено, Неопределено);
Модифицированность = Истина;
КонецПроцедуры
&НаСервере
Процедура УстановитьЗначениеДопРеквизитаДолжность(НаименованиеДопреквизитаДолжность, Должность)
УправлениеСвойствами.ПеренестиЗначенияИзРеквизитовФормыВОбъект(ЭтаФорма, Объект);
Если Объект.ДополнительныеРеквизиты.Количество() = 0 Тогда
Возврат;
КонецЕсли;
СвойствоТекущаяДолжность = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию(НаименованиеДопреквизитаДолжность);
НашлиСтроку = Ложь;
Для каждого Строка Из Объект.ДополнительныеРеквизиты Цикл
Если Строка.Свойство.Ссылка = СвойствоТекущаяДолжность Тогда
Строка.Значение = Должность;
НашлиСтроку = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если НЕ НашлиСтроку Тогда
НоваяСтрока = Объект.ДополнительныеРеквизиты.Добавить();
НоваяСтрока.Свойство = СвойствоТекущаяДолжность;
НоваяСтрока.Значение = Должность;
КонецЕсли;
УправлениеСвойствами.ЗаполнитьДополнительныеРеквизитыВФорме(ЭтаФорма, Объект);
ОбработатьУстановкуДействияДляДопреквизитов_Премия(Неопределено, Неопределено, Неопределено);
Модифицированность = Истина;
КонецПроцедуры
&НаКлиенте
Процедура УстановитьТолькоПросмотрДляПоля(НаименованиеДопРеквизита)
ДопРеквизитПоле = НайтиДопреквизитВФорме(НаименованиеДопРеквизита);
Если ДопРеквизитПоле <> Неопределено Тогда
ДопРеквизитПоле.ТолькоПросмотр = Истина;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура УстановитьТолькоПросмотрДляПолейДолжность()
Для Сч =1 По КоличествоСтрокВТаблицеПремия Цикл
УстановитьТолькоПросмотрДляПоля("Должность" + СокрЛП(Сч));
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура УстановитьЗначениеСвойстваПоляФормыДопРеквизита(НаименованиеДопРеквизита, СвойствоПоляФормы, ЗначениеСвойстваПоляФормы)
ДопРеквизитПоле = НайтиДопреквизитВФорме(НаименованиеДопРеквизита);
Если ДопРеквизитПоле <> Неопределено Тогда
Выполнить("ДопРеквизитПоле." + СвойствоПоляФормы + "=" + ЗначениеСвойстваПоляФормы);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура УстановитьКнопкаОткрытияЛожьДляПолейДолжность()
Для Сч =1 По КоличествоСтрокВТаблицеПремия Цикл
УстановитьЗначениеСвойстваПоляФормыДопРеквизита("Должность" + СокрЛП(Сч), "КнопкаОткрытия", "Ложь")
КонецЦикла;
КонецПроцедуры
#КонецОбласти
Таким образом, в документе получаем таблицу следующего вида:
При выборе сотрудника программно подставляется должность. При изменении суммы в "строке" пересчитывается поле Итого распределено.
Остается только перейти в Настройка и администрирование / Поддержка и обслуживание / Управление пользовательскими настройками и скопировать настройки документа всем (или избранным) пользователям. Это функционал БСП.
В реальной боевой базе (госучреждение) внутренний документ Премия содержит 30 строк. Таково максимальное количество сотрудников в отделе. Кроме того, настроен автозаполняемый шаблон Word, бизнес-процесс согласования-утверждения документа, настроены права, сделан отчет. Работают два года, все довольны. Конфигурация на полной поддержке. Это к тому, что на доп. реквизитах можно делать полноценную автоматизацию.
Боевая конфигурация ДГУ 2.1.9.3 работает на платформе 8.3.9.1850. Настоящая публикация готовилась на платформе 8.3.13.1690 в демо-версии ДО 2.1.12.2 (режим совместимости 8.3.8).
Здравствуйте.Решение хорошее. А вы не пробовали определить вид вкладки Свойства прямо в расширении в зависимости от внутреннего вида документа (программно)?
(1) А есть ли смысл усложнять? В данном случае и так будут отображаться только допреквизиты соответствующего вида документа.
(1) Программно в зависимости от вида документа менял заголовок вкладки «Свойства», например, на «Премия».
Не юзабельно. Таких документов возможно потребуется не один десяток. Настраивать каждый, писать отдельный код и прочее. Да и настройки скорее всего в конце концов поедут.
Для одного документов, возможно, рабочее решение, но не более.
А как юзабельно? Да, в ДО обычно не один десяток видов внутренних документов (а также входящих и исходящих), которые являются элементами справочника. И каждый вид нужно настраивать. Вы предлагаете не настраивать? Забить?
Настройки никуда не едут. Если пользователь сам испортит свои настройки, то ничто не мешает скопировать их ему от администратора или другого пользователя. Это очень просто.
Если Вы смотрели код, то могли заметить, что большая часть кода универсальна.
Что плохого в снятие конфигурации с поддержки? Если она выполнена грамотно. У заказчиков такие страхи обычно из за предыдущих «разработчиков» после которых уже было не обновить 1с. А тем более 1с документооборот конфигурация обновляется раз в два года)) Как в знаменитой фразе : «Разработка хорошая, но зачем»
(6) Если у организации есть фикси, который занимается конфигурацией, и есть уверенность, что он не уволится, то включение возможности изменения в принципе, конечно, не страшно. А если организация обращается к франчу, где движение кадров сопоставимо со скоростью смены времен года? Опыт подсказывает мне, что если есть возможность оставить на полной поддержке, то лучше оставить.