При разработке внешних обработок заполнения для конфигурации «Управление торговлей 11» (или ERP и КА) программисты часто сталкиваются с проблемой: данные в табличной части программно меняются, но на экране пользователя ничего не происходит. Особенно остро эта проблема проявляется в документе УстановкаЦенНоменклатуры. Рассмотрим подробнее, почему стандартные методы обновления формы не всегда работают и как правильно реализовать заполнение цен, чтобы пользователь сразу увидел результат.
Проанализируем архитектуру этого документа. В отличие от простых документов (например, «Реализация товаров и услуг»), где данные табличной части напрямую отображаются в таблице формы, документ УстановкаЦенНоменклатуры использует сложную визуальную схему. На форме отображается не сама табличная часть Товары, а динамически формируемая структура — Дерево цен или Таблица цен.
Эта структура строится как кросс-таблица: в строках находится номенклатура, а в колонках — виды цен. Сами колонки создаются программно при открытии формы или выборе видов цен. Когда мы программно перебираем Объект.Товары и меняем там реквизит Цена, визуальный элемент формы (дерево) об этом «не знает» и продолжает отображать старые значения, кэшированные при открытии.
Самый надежный, хотя и не самый «чистый» с точки зрения UX способ — это принудительная запись объекта в базу данных с последующим обновлением формы. Рассмотрим этот вариант на примере кода внешней обработки.
В форме внешней обработки (тип команды ОткрытиеФормы) мы можем получить ссылку на текущий документ через владельца формы. Выясним причину, по которой обычное присваивание может не сработать, и напишем правильный алгоритм на сервере:
&НаКлиенте
Процедура ВыполнитьЗаполнение(Команда)
// Получаем ссылку на документ из формы-владельца
Если ВладелецФормы = Неопределено Тогда
Возврат;
КонецЕсли;
СсылкаНаДокумент = ВладелецФормы.Объект.Ссылка;
// Выполняем серверную часть записи
ЗаполнитьИЗаписатьНаСервере(СсылкаНаДокумент);
// Обновляем форму владельца, чтобы она перечитала данные из БД
ВладелецФормы.Прочитать();
ПоказатьОповещениеПользователя("Цены успешно обновлены");
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьИЗаписатьНаСервере(СсылкаНаДок)
ДокОбъект = СсылкаНаДок.ПолучитьОбъект();
Для Каждого Стр Из ДокОбъект.Товары Цикл
// Например, установим цену 100 для определенного вида цены
Если Стр.ВидЦены.Наименование = "Оптовая" Тогда
Стр.Цена = 100;
КонецЕсли;
КонецЦикла;
ДокОбъект.Записать();
КонецПроцедуры
Важный нюанс: метод Прочитать() полностью сбрасывает состояние формы к состоянию объекта в базе данных. Если пользователь до нажатия кнопки вашей обработки внес какие-то изменения вручную и не сохранил их, эти изменения будут потеряны. Именно поэтому автор в обсуждении отмечал, что «приходится записывать документ», что не всегда удобно для бизнес-процесса.
Для более элегантного решения, которое позволит заполнить форму без обязательной записи в БД, следует использовать механизм БСП ДополнительныеОтчетыИОбработки с типом команды ЗаполнениеФормы. В этом случае в обработку передается параметр ЭтаФорма, предоставляющий доступ к экранным данным.
Разберем, как реализовать модуль обработки для этого случая. В функции СведенияОВнешнейОбработке укажем тип команды:
Функция СведенияОВнешнейОбработке() Экспорт
// ... параметры регистрации ...
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Идентификатор = "ЗаполнитьЦеныБезЗаписи";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыЗаполнениеФормы();
// ...
Возврат ПараметрыРегистрации;
КонецФункции
Теперь в модуле обработки (не в форме!) реализуем процедуру ВыполнитьКоманду. Здесь мы можем манипулировать данными формы напрямую через ДанныеФормыВЗначение:
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив, ПараметрыВыполнения) Экспорт
ФормаДокумента = ПараметрыВыполнения.ЭтаФорма;
ОбъектДокумента = ФормаДокумента.Объект;
// Переносим данные формы в объект для удобной работы
ДокОбъект = ДанныеФормыВЗначение(ОбъектДокумента, Тип("ДокументОбъект.УстановкаЦенНоменклатуры"));
Для Каждого Стр Из ДокОбъект.Товары Цикл
Стр.Цена = Стр.Цена * 1.1; // Увеличим все цены на 10%
КонецЦикла;
// Возвращаем измененные данные обратно в форму
ЗначениеВДанныеФормы(ДокОбъект, ФормаДокумента.Объект);
// Сообщаем форме, что данные изменились (звездочка в заголовке)
ФормаДокумента.Модифицированность = Истина;
// А теперь — самое главное! Обновление визуального дерева.
// В типовых УТ 11 в форме документа есть экспортные методы пересчета.
Попытка
ФормаДокумента.ОбновитьОтображениеЦен();
Исключение
// Если метод не экспортный или называется иначе,
// потребуется имитация изменения ключевых реквизитов
КонецПопытки;
КонецПроцедуры
Проанализируем ситуацию, если вы применили ЗначениеВДанныеФормы, но таблица на экране осталась пустой или со старыми ценами. В типовых конфигурациях 1С обновление ДереваЦен (той самой кросс-таблицы) завязано на серверные процедуры модуля формы.
Рассмотрим основные причины:
Цена_<УникальныйИдентификаторВидаЦены>. Если вы просто меняете ТЧ Товары, дерево не перестраивается автоматически.УстановкаЦенНоменклатуры обычно есть процедура ЗаполнитьДеревоЦен() (или аналогичная). Если она не является экспортной, вы не сможете вызвать её из внешней обработки напрямую.Совет: Если штатные методы обновления недоступны, можно попробовать «взломать» систему, программно изменив какой-нибудь реквизит формы, на который «подписано» обновление (например, перевыбрать виды цен программно), но это требует глубокого анализа кода конкретного релиза конфигурации.
Для корректного программного заполнения документа «Установка цен номенклатуры» в управляемом интерфейсе УТ 11 мы рекомендуем:
ДанныеФормыВЗначение и ЗначениеВДанныеФормы для работы с объектом без его записи.Модифицированность = Истина для формы-владельца.ВладелецФормы.Прочитать().Помните, что работа с управляемыми формами — это прежде всего работа с данными формы, а не с объектами базы данных. Понимание разницы между ними — ключ к созданию стабильных и удобных инструментов для пользователей.