При доработке типовых конфигураций, таких как «Управление торговлей 11», программисты часто сталкиваются с задачей добавления собственных полей на формы сложных обработок. Одной из таких обработок является рабочее место «Прайс-лист». Рассмотрим ситуацию: нам необходимо добавить новую колонку Продолжительность в реквизит формы ДеревоЦен, заполнить её данными из нашего регистра сведений и обеспечить сохранение изменений.
Проанализируем проблему, с которой столкнулся автор: колонка визуально добавляется, но при обновлении данных или закрытии окна настроек возникают ошибки, либо колонка просто исчезает, а данные не заполняются. Выясним причину такого поведения и разберем по шагам правильный алгоритм решения.
В УТ 11 рабочее место по установке цен очень тесно интегрировано с подсистемой компоновки данных (СКД) и общим модулем УстановкаЦенСервер. При нажатии кнопки «ОК» в форме настроек срабатывает процедура ПерейтиКУстановкеЦен(), которая запускает серверные методы построения дерева.
Главная «ловушка» заключается в том, что типовой механизм 1С при каждом пересчете цен или изменении настроек полностью очищает реквизиты формы. Система удаляет все динамически созданные колонки дерева и генерирует их заново на основе выбранных видов цен. Если вы программно создали колонку только при открытии формы (в ПриСозданииНаСервере), то после вызова типового перестроения интерфейса она будет уничтожена. При попытке вернуть данные с сервера на форму с помощью ЗначениеВРеквизитФормы система выдаст ошибку несоответствия структуры.
Чтобы избежать ошибок, нам необходимо встроить создание нашей колонки в жизненный цикл формы. Посмотрим на пример того, как перехватить перестроение дерева (например, в процедуре применения настроек):
ДеревоЦен.
&НаСервере
Процедура ПослеПримененияНастроек()
// 1. Удаляем колонку, если она осталась от предыдущих действий
УдалитьМоюКолонку();
// 2. Вызываем типовой метод перестроения дерева (типовой код 1С)
ПерейтиКУстановкеЦен(); // или другая вызываемая процедура
// 3. Создаем колонку заново
СоздатьМоюКолонку();
// 4. Заполняем колонку данными из базы
ЗаполнитьПродолжительностьВДереве();
КонецПроцедуры
Рассмотрим подробнее реализацию процедуры создания реквизитов и элементов формы с помощью метода ИзменитьРеквизиты:
&НаСервере
Процедура СоздатьМоюКолонку()
// Формируем массив добавляемых реквизитов
НовыеРеквизиты = Новый Массив;
ТипЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 2));
НовыеРеквизиты.Добавить(Новый РеквизитФормы("Продолжительность", ТипЧисло, "ДеревоЦен", "Продолжительность"));
// Применяем изменения к форме
ИзменитьРеквизиты(НовыеРеквизиты);
// Добавляем элемент управления в таблицу на форме
ЭлементДерева = Элементы.ДеревоЦен;
НовыйЭлемент = Элементы.Добавить("ДеревоЦенПродолжительность", Тип("ПолеФормы"), ЭлементДерева);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ПутьКДанным = "ДеревоЦен.Продолжительность";
КонецПроцедуры
Внедрять расчет нашего показателя непосредственно в сложные запросы СКД общего модуля — это плохая практика, которая усложнит дальнейшие обновления конфигурации. Наиболее надежный подход — это дозаполнение дерева (пост-обработка) после того, как типовой механизм завершил свою работу.
Разберем алгоритм заполнения:
РеквизитФормыВЗначение.Продолжительность.ЗначениеВРеквизитФормы.
&НаСервере
Процедура ЗаполнитьПродолжительностьВДереве()
ДЗ = РеквизитФормыВЗначение("ДеревоЦен");
// ... здесь код сбора массива номенклатуры и выполнения запроса к регистру ...
// В результате получаем Соответствие или ТаблицуЗначений с данными
Для Каждого СтрокаДерева Из ДЗ.Строки Цикл
// Обработка верхнего уровня и подчиненных строк
ЗаполнитьСтрокиРекурсивно(СтрокаДерева, ДанныеИзРегистра);
КонецЦикла;
// Возвращаем данные на форму
ЗначениеВРеквизитФормы(ДЗ, "ДеревоЦен");
КонецПроцедуры
Поскольку наше поле Продолжительность является пользовательским и данные хранятся отдельно (например, в неком регистре сведений), нам нужно обеспечить запись при редактировании. Существует два основных подхода:
1. Мгновенное сохранение:
При программном создании элемента формы (на шаге 1) мы можем назначить ему обработчик события ПриИзменении с помощью метода УстановитьДействие. Когда пользователь отредактирует ячейку, будет вызван серверный метод, который прочитает свойство Элементы.ДеревоЦен.ТекущиеДанные, получит ссылку на номенклатуру, новое значение продолжительности и точечно запишет набор записей в независимый регистр сведений.
2. Пакетное сохранение:
Если изменения предполагается вносить массово, лучше добавить на форму отдельную кнопку «Сохранить прайс-лист» или перехватить штатную команду записи. В этом случае мы выгружаем дерево цен с формы, обходим все строки в цикле, собираем измененные значения и записываем их в регистр сведений за одну транзакцию.
Используя данный архитектурный подход, вы сможете безопасно расширять функционал сложных рабочих мест 1С, не ломая типовую логику и обеспечивая стабильную работу ваших доработок при обновлениях системы.