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