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