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