Как программно управлять заполнением цен в УТ 11 при вводе на основании поступления?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

Многие разработчики, привыкшие к классической архитектуре 1С, сталкиваются с трудностями при попытке кастомизировать заполнение документа УстановкаЦенНоменклатуры в конфигурации "Управление торговлей 11" (УТ 11). Проблема заключается в том, что логика этого документа значительно отличается от стандартных документов системы: данные хранятся не в привычных табличных частях, доступных в модуле объекта, а в сложной динамической структуре на форме. Рассмотрим подробнее, как устроена эта подсистема и как мы можем внедрить в неё собственные алгоритмы расчета.

Почему стандартная ОбработкаЗаполнения не подходит?

Разберем ситуацию: нам необходимо, чтобы при создании установки цен на основании "Приобретения товаров и услуг" система не просто подтягивала закупочные цены, но и рассчитывала розничные или оптовые цены по кастомному алгоритму (например, используя индивидуальные наценки из дополнительных реквизитов номенклатуры). Проанализировав модуль объекта, мы обнаружим, что процедура ОбработкаЗаполнения практически не содержит кода, отвечающего за расчет цен. Это происходит потому, что 1С спроектировала этот документ как интерактивное рабочее место.

Основным реквизитом формы документа является ДеревоЦен. Эта структура данных формируется динамически в зависимости от выбранных видов цен и настроек их компоновки. Расчеты происходят "на лету" с использованием клиент-серверных вызовов и фоновых заданий. Таким образом, если мы хотим вмешаться в автоматику, нам нужно работать именно с данными формы.

Типовой механизм настройки заполнения

Прежде чем переходить к кодингу, проанализируем, все ли возможности типового функционала мы задействовали. Для того чтобы документ заполнялся корректно при вводе на основании, должны быть выполнены следующие условия:

  1. В справочнике Виды цен для закупочной цены должен быть установлен флаг При вводе на основании документов поставки. Именно этот признак заставляет систему искать данные в документе-основании.
  2. Для зависимых цен (например, розничных) должен быть выбран способ задания цены Рассчитывать по другим видам цен. В формуле обязательно должен присутствовать базовый вид цены (закупочная).
  3. В настройках параметров системы должен быть разрешен фоновый расчет цен, если объем данных велик.

Если эти настройки корректны, но нам всё равно нужно изменить логику (например, добавить процент наценки, который хранится в свойствах конкретной карточки товара), мы переходим к программному решению.

Решение через модификацию дерева цен на форме

Посмотрим на практический способ решения задачи, предложенный опытными разработчиками. Если нам нужно внедрить свой алгоритм расчета в интерфейсную логику, мы можем использовать метод "обхода" сложной структуры дерева цен. Разберем этот алгоритм по шагам:

Шаг 1: Выгрузка данных в таблицу значений. Поскольку напрямую пересчитывать дерево значений на форме не всегда удобно из-за его иерархичности и динамических колонок, мы выгружаем его содержимое в плоскую таблицу значений.

Шаг 2: Программный пересчет. В полученной таблице мы находим нужные нам колонки (имена колонок для видов цен обычно соответствуют их уникальным идентификаторам или имеют префикс Цена_) и применяем свои формулы.

Шаг 3: Загрузка данных обратно. После модификации данных мы загружаем таблицу обратно в структуру формы.

Проанализируем пример кода, который можно разместить в расширении для формы документа УстановкаЦенНоменклатуры в процедуре ПриОткрытии (после вызова типового заполнения) или в специально созданной команде:


&НаСервере
Процедура ПересчитатьЦеныПоДопСвойствамНаСервере()
    
    // Выгружаем дерево цен формы в таблицу значений
    ТаблицаЦен = ДеревоЦен.ПолучитьЭлементы();
    
    Для Каждого СтрокаНоменклатура Из ТаблицаЦен Цикл
        
        НоменклатураСсылка = СтрокаНоменклатура.Номенклатура;
        
        // Получаем нашу индивидуальную наценку из доп. реквизита
        ПроцентНаценки = ОбщегоНазначения.ЗначениеДопРеквизита(НоменклатураСсылка, "ПроцентИндивидуальнойНаценки");
        
        Если ПроцентНаценки <> 0 Тогда
            // Предположим, у нас есть колонка с закупочной ценой и розничной
            // В реальной УТ 11 имена колонок динамические, их нужно найти по ID вида цены
            ЗакупочнаяЦена = СтрокаНоменклатура.Цена_Закупочная;
            СтрокаНоменклатура.Цена_Розничная = ЗакупочнаяЦена * (1 + ПроцентНаценки / 100);
        КонецЕсли;
        
    КонецЦикла;

КонецПроцедуры

Важное замечание: В типовой конфигурации УТ 11 имена колонок в ДеревоЦен формируются динамически. Чтобы найти нужную колонку программно, следует обратиться к коллекции ВидыЦен, которая также присутствует на форме, и сопоставить ссылку на вид цены с идентификатором колонки в дереве.

Работа с фоновыми заданиями и задержкой заполнения

Выясним причину, по которой отладчик часто не "ловит" момент заполнения цен. В современных версиях УТ 11 (начиная с 11.4) расчет цен при вводе на основании часто выполняется в фоновом задании. Это сделано для того, чтобы пользователь не ждал окончания расчетов при большом количестве номенклатуры (например, более 1000 позиций).

Если вы пытаетесь перехватить данные в момент создания документа, они могут быть еще не рассчитаны. В этом случае правильнее всего встраиваться в механизмы общих модулей, таких как УстановкаЦенНоменклатурыЛогика или использовать обработчики ожидания на форме, которые проверяют статус завершения фонового задания расчета цен.

Использование расширений для глубокой кастомизации

Рассмотрим более продвинутый метод — использование расширения для подмены типовой логики формирования таблицы данных перед тем, как она попадет в интерфейс. Основная точка входа для подготовки данных при заполнении на основании — это серверные функции в общем модуле УстановкаЦенНоменклатурыВызовСервера.

Проанализируем ситуацию: если мы хотим, чтобы наши изменения учитывались системой как "штатные" (чтобы работали стандартные проверки и флаги модификации), нам следует перехватить процедуру ЗаполнитьЦеныПоДокументу. В расширении это будет выглядеть примерно так:


&Вместо("ЗаполнитьЦеныПоДокументу")
Процедура Мой_ЗаполнитьЦеныПоДокументу(ПараметрыЗаполнения)
    
    // Вызываем стандартную логику для получения базовых данных
    ПродолжитьВызов(ПараметрыЗаполнения);
    
    // Теперь ПараметрыЗаполнения.АдресРезультатаВВременномХранилище содержит таблицу
    // Мы можем извлечь её, модифицировать и положить обратно
    Данные = ПолучитьИзВременногоХранилища(ПараметрыЗаполнения.АдресРезультатаВВременномХранилище);
    
    // Цикл по модификации данных (своя наценка, сложные округления и т.д.)
    Для Каждого СтрокаДанных Из Данные Цикл
        // Ваш код модификации
    КонецЦикла;
    
    ПоместитьВоВременноеХранилище(Данные, ПараметрыЗаполнения.АдресРезультатаВВременномХранилище);
    
КонецПроцедуры

Такой подход считается наиболее "чистым" с точки зрения архитектуры 1С, так как он не вмешивается в визуальные компоненты формы напрямую, а работает с данными на уровне бизнес-логики сервера. Это гарантирует, что при обновлении конфигурации ваш код с меньшей вероятностью "сломает" интерфейс документа.

Подведем итог: Необычная работа заполнения цен в УТ 11 обусловлена тем, что это сложный интерактивный механизм, а не простой документ. Для эффективной работы с ним используйте либо прямое манипулирование ДеревоЦен на форме через выгрузку в таблицу значений, либо перехватывайте подготовку данных в общих модулях через расширения.

← На главную