В практике разработки на платформе 1С:Предприятие часто возникает задача по внедрению дополнительного контроля данных в типовые документы, не изменяя саму конфигурацию (или минимизируя изменения в модулях объектов). Одним из наиболее элегантных и правильных способов решения такой задачи является использование Подписок на события. В этой статье мы подробно разберем ситуацию, когда необходимо запретить проведение документа РеализацияТоваровУслуг, если ставка НДС в его табличной части не соответствует статусу организации как плательщика НДС.
Рассмотрим конкретный кейс: в информационной базе ведется учет по организации, чья учетная политика хранится в регистре сведений УчетнаяПолитикаНалоговыйУчет. Нам необходимо реализовать следующую логику:
РеализацияТоваровУслуг программа должна обратиться к регистру сведений и выяснить, является ли организация плательщиком НДС на дату документа.Товары.Для реализации этой логики мы будем использовать подписку на событие ОбработкаПроведения. Это позволит нам выполнять проверку в момент записи документа в базу данных в режиме проведения, обеспечивая целостность данных.
Прежде чем создавать саму подписку, нам необходимо подготовить место для размещения программного кода. Создадим новый общий модуль, назовем его, например, _ПроверкаНДС. В свойствах модуля обязательно должны быть установлены флажки Сервер и Вызов сервера (так как проведение документа всегда происходит на стороне сервера).
Проанализируем структуру процедуры, которая будет служить обработчиком события. Она должна иметь строго определенный набор параметров, соответствующий событию ОбработкаПроведения для документов:
Процедура _ПроверкаНДСОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
// Здесь будет располагаться наша логика
КонецПроцедуры
Параметр Источник передает нам объект документа, который в данный момент проводится. Параметр Отказ — это булево значение, которое мы установим в Истина, если проверка не будет пройдена.
Для того чтобы понять, нужно ли вообще проверять ставку НДС, мы должны обратиться к регистру сведений. Разберем, как это сделать эффективно. Мы будем использовать метод СрезПоследних, который позволяет получить актуальное состояние настроек на конкретную дату.
Важный нюанс: если мы просто вызовем СрезПоследних(), система может вернуть данные по всем организациям сразу. Поэтому мы применим фильтр по конкретной организации, указанной в документе.
// Формируем структуру отбора для регистра
Отбор = Новый Структура("Организация", Источник.Организация);
ДанныеПолитики = РегистрыСведений.УчетнаяПолитикаНалоговыйУчет.СрезПоследних(Источник.Дата, Отбор);
Если ДанныеПолитики.Количество() = 0 Тогда
Сообщить("Учетная политика для организации не настроена!");
Возврат;
КонецЕсли;
// Проверяем ресурс регистра
Если Не ДанныеПолитики[0].ОрганизацияЯвляетсяПлательщикомНДС Тогда
// Если организация не плательщик НДС, проверка ставок не требуется
Возврат;
КонецЕсли;
Проанализируем способ поиска нужной ставки. В 1С ставки НДС обычно хранятся в справочнике СтавкиНДС. Поиск по наименованию (например, "12%") является рабочим, но потенциально опасным методом, так как пользователь может случайно изменить название элемента в справочнике. Однако, в рамках нашей задачи рассмотрим этот вариант как наиболее наглядный.
ПравильнаяСтавка = Справочники.СтавкиНДС.НайтиПоНаименованию("12%");
Если ПравильнаяСтавка.Пустая() Тогда
Сообщить("В справочнике 'Ставки НДС' не найден элемент с наименованием '12%'!");
Отказ = Истина;
Возврат;
КонецЕсли;
Теперь, когда у нас есть все необходимые данные (подтверждение статуса плательщика и ссылка на правильную ставку), проанализируем табличную часть документа. Нам нужно перебрать все строки коллекции Товары и сравнить значение реквизита СтавкаНДС с нашим эталоном.
Для Каждого СтрокаТЧ Из Источник.Товары Цикл
Если СтрокаТЧ.СтавкаНДС <> ПравильнаяСтавка Тогда
Отказ = Истина;
// Информируем пользователя, указывая номер строки для удобства исправления
ТекстСообщения = "Ошибка в строке №" + СтрокаТЧ.НомерСтроки + ": для плательщиков НДС ставка должна быть 12%!";
Сообщить(ТекстСообщения);
КонецЕсли;
КонецЦикла;
Обратите внимание: установка Отказ = Истина внутри цикла гарантирует, что если хотя бы одна строка будет заполнена неверно, документ не будет проведен. При этом цикл продолжится, и пользователь получит сообщения обо всех ошибочных строках сразу.
Рассмотрим несколько профессиональных советов, которые помогут сделать это решение более надежным:
СрезПоследних, использование объекта Запрос считается более правильным тоном в разработке 1С. Запрос работает быстрее и позволяет получить данные более гибко.СтавкиНДС имеет предопределенные элементы, лучше обращаться к ним напрямую через Справочники.СтавкиНДС.НДС12, чтобы избежать ошибок при переименовании элементов пользователями.Сообщить() рекомендуется использовать объект СообщениеПользователю. Это позволит "привязать" сообщение к конкретному полю документа, и пользователь сможет кликнуть по нему, чтобы сразу перейти к исправлению ошибки.Сведем все части воедино в законченную процедуру, которую вы сможете использовать в своем общем модуле:
&НаСервере
Процедура _ПроверкаНДСОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт
// 1. Получаем настройки учетной политики на дату документа
Отбор = Новый Структура("Организация", Источник.Организация);
ТаблицаПолитики = РегистрыСведений.УчетнаяПолитикаНалоговыйУчет.СрезПоследних(Источник.Дата, Отбор);
Если ТаблицаПолитики.Количество() = 0 Тогда
// Если политики нет, возможно, стоит запретить проведение или просто выйти
Возврат;
КонецЕсли;
// 2. Если организация не плательщик НДС — выходим из проверки
Если Не ТаблицаПолитики[0].ОрганизацияЯвляетсяПлательщикомНДС Тогда
Возврат;
КонецЕсли;
// 3. Находим эталонную ставку
Ставка12 = Справочники.СтавкиНДС.НайтиПоНаименованию("12%");
// 4. Проверяем строки документа
Для Каждого ТекСтрока Из Источник.Товары Цикл
Если ТекСтрока.СтавкаНДС <> Ставка12 Тогда
Отказ = Истина;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Для плательщиков НДС ставка должна быть 12% (ошибка в строке " + ТекСтрока.НомерСтроки + ")";
Сообщение.Поле = "Товары[" + (ТекСтрока.НомерСтроки - 1) + "].СтавкаНДС";
Сообщение.УстановитьДанные(Источник);
Сообщение.Сообщить();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
После написания кода не забудьте создать сам объект Подписка на событие в дереве конфигурации. В качестве источника выберите ДокументОбъект.РеализацияТоваровУслуг, событие — ОбработкаПроведения, а в качестве обработчика укажите созданную нами процедуру _ПроверкаНДСОбработкаПроведения. Теперь ваша система надежно защищена от ошибок ввода данных при оформлении реализаций.