Как программно пересчитать сумму, НДС и итоги в документе Приобретение товаров и услуг в УТ 11

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

При разработке внешних обработок для 1С:Управление торговлей 11 (а также ERP 2 и Комплексной автоматизации 2) часто возникает задача массового изменения цен в документах поступления. Однако простого изменения значения в колонке Цена недостаточно. В современных конфигурациях табличные части документов содержат множество зависимых реквизитов: сумма без НДС, сумма НДС, сумма с НДС, сумма взаиморасчетов и различные скидки. Если изменить только цену, данные в документе станут некорректными («поползет» математика), а итоговые суммы в подвале документа не обновятся.

В этой статье мы разберем, как правильно использовать типовой механизм пересчета на стороне сервера, чтобы система сама актуализировала все связанные показатели, как если бы пользователь изменил цену вручную в интерфейсе.

Проблема прямого изменения реквизитов

Когда мы работаем с объектом документа на сервере, мы часто совершаем ошибку, ограничиваясь кодом вида СтрокаТЧ.Цена = НоваяЦена;. В типовых решениях на управляемых формах за каждым изменением реквизита стоит сложная логика, прописанная в модулях ОбработкаТабличнойЧастиКлиент и ОбработкаТабличнойЧастиСервер. Чтобы не изобретать велосипед и гарантировать точность расчетов (учитывая настройки налогообложения, валюту и соглашения), нам необходимо вызвать эти штатные процедуры.

Шаг 1. Подготовка структуры действий для пересчета

Для управления процессом пересчета типовые механизмы используют специальный объект — СтруктураДействий. В этой структуре мы указываем системе, что именно нужно сделать с каждой строкой табличной части. Рассмотрим, какие параметры нам понадобятся.

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


&НаСервереБезКонтекста
Функция ПолучитьЗависимыеРеквизиты()
    Возврат Новый Структура(
        "БезВозвратнойТары",
        "Сумма,СуммаНДС,СуммаСНДС,СуммаРучнойСкидки");
КонецФункции

Шаг 2. Реализация основного алгоритма на сервере

Теперь рассмотрим процедуру, которая обходит отобранные документы, меняет цену и запускает пересчет. Обратите внимание на использование общего модуля ОбработкаТабличнойЧастиКлиентСервер для получения параметров НДС и ОбработкаТабличнойЧастиСервер для выполнения самих расчетов.


&НаСервере
Процедура ИзменитьЦеныИПересчитатьНаСервере() 
    
    // Подготовим кэш для ускорения работы, если строк в документах много
    КэшированныеЗначения = ОбработкаТабличнойЧастиСервер.ПодготовитьКэшированныеЗначения();
    
    Для Каждого СтрокаВыбора Из СписокДокументовНаФорме Цикл
        Если Не СтрокаВыбора.Отметка Тогда 
            Продолжить;
        КонецЕсли; 
        
        ДокументОбъект = СтрокаВыбора.Ссылка.ПолучитьОбъект();     
        
        // 1. Формируем структуру инструкций для пересчета
        ПараметрыНДС = ОбработкаТабличнойЧастиКлиентСервер.ПараметрыПересчетаСуммыНДСВСтрокеТЧ(ДокументОбъект);
        
        СтруктураДействий = Новый Структура;
        СтруктураДействий.Вставить("ПересчитатьСуммуНДС", ПараметрыНДС);
        СтруктураДействий.Вставить("ПересчитатьСуммуСНДС", ПараметрыНДС);
        СтруктураДействий.Вставить("ПересчитатьСумму");
        СтруктураДействий.Вставить("ПересчитатьСуммуСУчетомРучнойСкидки", Новый Структура("Очищать", Ложь));
        СтруктураДействий.Вставить("ОчиститьСуммуВзаиморасчетов");
        СтруктураДействий.Вставить("ЗаполнитьДубликатыЗависимыхРеквизитов", ПолучитьЗависимыеРеквизиты());
        
        // 2. Обходим строки табличной части "Товары"
        Для Каждого СтрокаТовар Из ДокументОбъект.Товары Цикл
            // Например, увеличиваем цену на 50%
            СтрокаТовар.Цена = СтрокаТовар.Цена * 1.5;   
            
            // Вызываем типовой серверный метод обработки строки
            ОбработкаТабличнойЧастиСервер.ОбработатьСтрокуТЧ(СтрокаТовар, СтруктураДействий, КэшированныеЗначения);
        КонецЦикла;
        
        // 3. После обработки всех строк необходимо актуализировать итоговые показатели документа
        // В новых версиях УТ это может быть вызов метода модуля менеджера или объекта
        ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
        
    КонецЦикла;  
        
КонецПроцедуры

Разбор ключевых команд пересчета

Выясним, за что отвечают основные элементы СтруктураДействий, чтобы вы могли гибко настраивать свою обработку:

  1. ПересчитатьСумму — на основании новой цены и количества вычисляет общую сумму строки.
  2. ПересчитатьСуммуНДС — рассчитывает налог. Важно передать сюда структуру ПараметрыНДС, так как она содержит информацию о ставке (сверху или в том числе) и правилах налогообложения документа.
  3. ОчиститьСуммуВзаиморасчетов — полезно, если валюта документа отличается от валюты договора. После очистки система при проведении или при вызове дополнительных методов (например, ПересчитатьСуммуВзаиморасчетов) заполнит ее актуальными данными по курсу.
  4. ЗаполнитьДубликатыЗависимыхРеквизитов — в УТ 11 некоторые данные дублируются в скрытые реквизиты для оптимизации запросов, этот ключ поддерживает их консистентность.

Оптимизация производительности (Кэширование)

Обратите внимание на параметр КэшированныеЗначения. Проанализируем ситуацию: если в вашем документе 500 строк, и вы вызываете ОбработатьСтрокуТЧ в цикле, система при каждом вызове может пытаться считать настройки учетной политики или параметры валют. Передача заранее подготовленного кэша (функция ПодготовитьКэшированныеЗначения) позволяет выполнить эти тяжелые операции один раз в начале процедуры, что ускоряет обработку в несколько раз.

Дополнительно: Множественный отбор номенклатуры

Часто в таких обработках требуется фильтровать документы не по одной позиции, а по списку. Рассмотрим, как это реализовать правильно:

Во-первых, на форме обработки создайте реквизит с типом СписокЗначений (укажите тип элементов — СправочникСсылка.Номенклатура). Это позволит пользователю выбирать несколько товаров через стандартное окно подбора.

Во-вторых, при написании запроса для поиска документов используйте оператор В вместо =. Посмотрим на пример фрагмента запроса:


ТекстЗапроса = "ВЫБРАТЬ РАЗЛИЧНЫЕ
               |    Товары.Ссылка КАК Документ
               |ИЗ
               |    Документ.ПриобретениеТоваровУслуг.Товары КАК Товары
               |ГДЕ
               |    Товары.Номенклатура В (&СписокНоменклатуры)
               |    И Товары.Ссылка.Проведен";

Запрос.УстановитьПараметр("СписокНоменклатуры", Объект.РеквизитСписокНоменклатуры);

Важные рекомендации при работе с документами

При массовом изменении объектов всегда учитывайте следующие моменты:

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

← На главную