Как программно изменить ставку НДС у всех элементов группы справочника «Номенклатура» в 1С:Управление торговлей 11.1?

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

При работе с конфигурацией 1С:Управление торговлей 11.1, особенно если она имеет многочисленные доработки, мы можем столкнуться с необходимостью массового изменения реквизитов, таких как ставка НДС, у элементов справочника «Номенклатура». Часто типовые механизмы, вроде «Группового изменения реквизитов», оказываются неработоспособными, а поле для ручного изменения ставки НДС на форме элемента справочника может быть заблокировано. В такой ситуации возникает потребность в программном решении. Для разблокировки этого поля можно применить расширение для изменения ставки НДС через групповое изменение реквизитов.

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

Причины возникновения проблемы и особенности УТ 11.1

Прежде чем перейти к решению, выясним, почему мы сталкиваемся с такими сложностями:

  1. Блокировка поля «Ставка НДС»: Система может блокировать поле «Ставка НДС» на форме элемента номенклатуры, если реквизит считается «ключевым» или уже использовался в документах. Это делается для предотвращения случайных изменений, которые могут привести к нарушению корректности учета и расчетов.
  2. Неработоспособность типовых обработок: Из-за значительных доработок конфигурации стандартное поведение системы может быть изменено. Это часто приводит к тому, что типовые механизмы, такие как «Групповое изменение реквизитов» или «Поиск и замена значений», не работают или вызывают ошибки совместимости.
  3. Историчность ставок НДС: В более поздних версиях УТ 11 (начиная, например, с 11.5.25.63) ставка НДС для номенклатуры является периодическим реквизитом и хранится в специальном регистре сведений «Ставки НДС номенклатуры». Это позволяет устанавливать дату начала действия новой ставки. В УТ 11.1 этот механизм мог быть менее развит, что упрощает прямое изменение реквизита, но в более актуальных конфигурациях требует работы с регистром.
  4. Отсутствие ставки 20% в старых версиях: Для УТ 11.1, 11.2 и 11.3 ставка НДС 20% изначально могла отсутствовать в перечислениях системы, так как она была введена с 1 января 2019 года (заменив 18%). Мы должны убедиться, что соответствующее значение присутствует в перечислении Перечисления.СтавкиНДС. Если его нет, нам потребуется его создать, что может потребовать обновления конфигурации или ручного вмешательства.

Программное изменение ставки НДС: пошаговое руководство

Мы будем использовать программный код для обхода всех элементов нужной группы справочника и принудительного изменения ставки НДС. Рассмотрим процесс по шагам, с учетом возможных ошибок и их исправлений.

Шаг 1: Инициализация параметров запроса

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

В первоначальной попытке могла быть допущена ошибка, когда вместо Перечисления.СтавкиНДС.Ставка20 случайно указывалось Перечисления.СтавкиНДС.БезНДС. Мы должны всегда проверять, какое значение перечисления мы используем.

Рассмотрим пример правильной инициализации:


Группа = Справочники.Номенклатура.НайтиПоНаименованию("ПрограммноеОбеспечение");
Если Группа = Неопределено Тогда
    Сообщить("Группа номенклатуры 'ПрограммноеОбеспечение' не найдена!");
    Возврат;
КонецЕсли;

НДС20 = Перечисления.СтавкиНДС.Ставка20; // Правильно указываем целевую ставку НДС

Запрос = Новый Запрос;

Мы всегда должны проверять, найдена ли группа, чтобы избежать ошибок при выполнении запроса.

Шаг 2: Формирование и выполнение запроса

Далее мы формируем запрос, который выберет все элементы номенклатуры, принадлежащие нашей группе, не являющиеся группами сами по себе и имеющие ставку НДС, отличную от 20%.


Запрос.Текст = "ВЫБРАТЬ
               |    Номенклатура.Ссылка,
               |    Номенклатура.ЭтоГруппа,
               |    Номенклатура.Родитель,
               |    Номенклатура.Наименование,
               |    Номенклатура.СтавкаНДС
               |ИЗ
               |    Справочник.Номенклатура КАК Номенклатура
               |ГДЕ
               |    Номенклатура.Родитель = &Группа
               |    И Номенклатура.ЭтоГруппа = &Ложь
               |    И Номенклатура.СтавкаНДС <> &НДС20";

Запрос.УстановитьПараметр("Группа", Группа);
Запрос.УстановитьПараметр("Ложь", Ложь);
Запрос.УстановитьПараметр("НДС20", НДС20);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

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

Шаг 3: Корректное изменение и запись объекта

Это самый критичный шаг. Распространенной ошибкой является многократный вызов ПолучитьОбъект() в цикле. Каждый вызов Выборка.Ссылка.ПолучитьОбъект() создает новый экземпляр объекта из базы данных. Если мы изменяем реквизит одного объекта, а затем пытаемся записать другой, наши изменения не сохранятся.

Мы должны получить объект один раз, внести все необходимые изменения, а затем один раз записать этот же объект. Кроме того, для обхода блокировок и проверок, которые могут быть установлены в конфигурации (особенно в доработанных), мы можем использовать флаг ОбменДанными.Загрузка = Истина.

Этот флаг сигнализирует системе, что данные загружаются в режиме обмена, что часто отключает часть проверок и бизнес-логики, которые могли бы препятствовать записи. После записи объекта мы всегда должны вернуть флаг в исходное состояние (Ложь), чтобы не повлиять на дальнейшую работу системы.

Рассмотрим исправленный и рекомендуемый подход:


// Включаем режим обмена данными, чтобы обойти возможные блокировки и проверки
ОбменДанными.Загрузка = Истина;

Пока Выборка.Следующий() Цикл
    Попытка
        ОбъектНоменклатура = Выборка.Ссылка.ПолучитьОбъект(); // Получаем объект один раз
        ОбъектНоменклатура.СтавкаНДС = НДС20; // Изменяем реквизит
        ОбъектНоменклатура.Записать(); // Записываем измененный объект
        Сообщить("Успешно изменена ставка НДС для номенклатуры: " + ОбъектНоменклатура.Наименование);
    Исключение Как Искл
        Сообщить("Ошибка при изменении ставки НДС для номенклатуры " + Выборка.Наименование + ": " + Искл.Описание);
    КонецПопытки;
КонецЦикла;

// Выключаем режим обмена данными
ОбменДанными.Загрузка = Ложь;

Сообщить("Процесс изменения ставок НДС завершен.");

Оборачивание записи в блок Попытка...Исключение позволяет нам обрабатывать возможные ошибки для каждого элемента по отдельности и продолжить выполнение обработки, даже если с одним из элементов возникли проблемы. Это очень полезно при массовых изменениях.

Итоговый пример кода обработки

Соберем все шаги в единый код, который можно использовать как внешнюю обработку или часть модуля:


&НаКлиенте
Процедура ВыполнитьИзменениеСтавкиНДС(Команда)
    // Необходимо подтверждение пользователя перед выполнением критичных операций
    Если Не Вопрос("Вы уверены, что хотите изменить ставку НДС для всех элементов выбранной группы на 20%?", РежимДиалогаВопрос.ДаНет, 60) = КодВозвратаДиалога.Да Тогда
        Возврат;
    КонецЕсли;
    
    // Вызов серверной процедуры
    ВыполнитьИзменениеСтавкиНДСНаСервере();
    
КонецПроцедуры

&НаСервере
Процедура ВыполнитьИзменениеСтавкиНДСНаСервере()

    Сообщить("Начинаем процесс изменения ставок НДС...", СтатусСообщения.Информация);

    // Шаг 1: Инициализация параметров запроса
    Группа = Справочники.Номенклатура.НайтиПоНаименованию("ПрограммноеОбеспечение");
    Если Группа = Неопределено Тогда
        Сообщить("Группа номенклатуры 'ПрограммноеОбеспечение' не найдена! Проверьте наименование.", СтатусСообщения.Ошибка);
        Возврат;
    КонецЕсли;

    // Убедимся, что ставка 20% существует в перечислениях
    Если Не Перечисления.СтавкиНДС.ЗначениеДоступно("Ставка20") Тогда
        Сообщить("Внимание: Ставка НДС 20% отсутствует в списке доступных перечислений! 
                  |Возможно, требуется обновление конфигурации или ручное добавление значения.
                  |Изменение ставки невозможно.", СтатусСообщения.Ошибка);
        Возврат;
    КонецЕсли;
    НДС20 = Перечисления.СтавкиНДС.Ставка20; 

    Запрос = Новый Запрос;

    // Шаг 2: Формирование и выполнение запроса
    Запрос.Текст = "ВЫБРАТЬ
                   |    Номенклатура.Ссылка,
                   |    Номенклатура.ЭтоГруппа,
                   |    Номенклатура.Родитель,
                   |    Номенклатура.Наименование,
                   |    Номенклатура.СтавкаНДС
                   |ИЗ
                   |    Справочник.Номенклатура КАК Номенклатура
                   |ГДЕ
                   |    Номенклатура.Родитель В ИЕРАРХИИ (&Группа)
                   |    И Номенклатура.ЭтоГруппа = &Ложь
                   |    И Номенклатура.СтавкаНДС <> &НДС20"; // Исключаем уже установленные ставки

    Запрос.УстановитьПараметр("Группа", Группа);
    Запрос.УстановитьПараметр("Ложь", Ложь);
    Запрос.УстановитьПараметр("НДС20", НДС20);

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

    // Шаг 3: Корректное изменение и запись объекта
    ПересчитаноЭлементов = 0;
    
    // Включаем режим обмена данными, чтобы обойти возможные блокировки и проверки
    ОбменДанными.Загрузка = Истина;

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

    // Выключаем режим обмена данными
    ОбменДанными.Загрузка = Ложь;

    Сообщить("Процесс изменения ставок НДС завершен. Изменено элементов: " + ПересчитаноЭлементов, СтатусСообщения.Информация);

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

В этом примере мы добавили проверку Перечисления.СтавкиНДС.ЗначениеДоступно("Ставка20"), чтобы убедиться в наличии необходимого значения НДС перед началом обработки. Также запрос был изменен с Родитель = &Группа на Родитель В ИЕРАРХИИ (&Группа), чтобы обрабатывать все элементы внутри группы, включая вложенные подгруппы. Это обеспечивает более полное покрытие, если такая иерархия присутствует.

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

  1. Всегда работайте на тестовой базе: Прежде чем применять любые программные изменения в рабочей базе, мы должны обязательно протестировать их на актуальной копии. Это поможет избежать непредвиденных проблем и потери данных.
  2. Проверьте наличие ставки 20% в перечислениях: Как уже упоминалось, в старых версиях УТ 11.1 ставка 20% может отсутствовать. Если это так, мы должны либо обновить конфигурацию до версии, где эта ставка уже есть, либо рассмотреть возможность ручного добавления значения в перечисление (что не рекомендуется без глубокого понимания последствий).
  3. Учитывайте влияние на существующие документы: Изменение ставки НДС в карточке номенклатуры не изменяет ставки НДС в уже проведенных документах. В новых документах ставка будет подтягиваться из карточки. Если нам требуется изменить ставки НДС в старых документах, это отдельная задача, требующая дополнительной обработки.
  4. Роль регистра сведений «Ставки НДС номенклатуры»: Если в нашей конфигурации (особенно после обновлений или доработок) реализовано периодическое хранение ставок НДС через регистр сведений «Ставки НДС номенклатуры», то одного изменения реквизита в справочнике может быть недостаточно. Нам потребуется также корректно записать новую запись в этот регистр с указанием периода действия ставки. Это более сложная задача, требующая обращения к функционалу регистра. В УТ 11.1 обычно достаточно прямого изменения реквизита.
  5. Резервное копирование: Перед любыми массовыми изменениями всегда делайте полное резервное копирование информационной базы. Для автоматизации создания резервных копий перед проведением технических работ на базах можно использовать программу для регулярного архивирования и тестирования 1С.

Альтернативные методы массового изменения (для справки)

Хотя в нашем случае типовые обработки не сработали из-за доработок, полезно знать о них:

  1. Рабочее место «Замена ставок НДС»: В более поздних версиях УТ 11 (начиная с 11.5.25.63) существует специальное рабочее место «Замена ставок НДС» в разделе «НСИ и администрирование». Оно позволяет выполнить групповую замену ставок НДС в карточках номенклатуры, видов номенклатуры и договоров с указанием заменяемой ставки, новой ставки и даты начала ее действия.
  2. Внешние обработки: Существует множество внешних обработок для массового изменения данных, доступных на различных ресурсах. Некоторые из них могут быть адаптированы для работы с периодическими ставками НДС или спецификой доработанных конфигураций. Однако мы должны быть осторожны и проверять их код перед использованием.
  3. Обработка через Excel: Для больших объемов данных иногда проще выгрузить номенклатуру в табличный документ (например, Excel), изменить ставки там, а затем загрузить обратно с помощью типовых или доработанных механизмов загрузки из табличных документов. Этот метод требует осторожности при сопоставлении данных.

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

← На главную