Приветствуем вас, уважаемые коллеги! Сегодня мы детально разберем одну из классических проблем, с которой сталкиваются разработчики при поддержке и модернизации нетиповых конфигураций на платформе 1С:Предприятие 7.7. Речь пойдет об изменении типа реквизита на периодический (на примере ставки НДС в справочнике «Номенклатура» в конфигурации «Торговля и Склад 7.7») и о том, как бороться со всплывающими интерактивными диалоговыми окнами при записи элемента. Мы также обсудим архитектурную сторону этого вопроса и выясним, почему делать ставку НДС периодическим реквизитом — это далеко не лучшее решение, и как можно реализовать эту задачу гораздо изящнее и безопаснее для базы данных.
Когда мы изменяем тип реквизита в метаданных на периодический, платформа 1С 7.7 начинает автоматически отслеживать историю его изменений. По умолчанию при попытке сохранить элемент справочника (нажатием кнопок «Записать» или «ОК»), система открывает стандартное интерактивное окно с вопросом о дате, с которой необходимо установить новое значение. Это происходит даже в тех случаях, когда значение реквизита на форме визуально не менялось.
Платформа видит, что на форме присутствует периодический реквизит, и считает его модифицированным при любой записи объекта. Если конфигурация активно используется пользователями, постоянное появление этого окна начинает их сильно раздражать и существенно замедляет ежедневную работу.
Для управления поведением диалогового окна при записи периодических реквизитов во встроенном языке 1С 7.7 существует специальная функция СохранениеПериодическихРеквизитов(). Рассмотрим подробнее синтаксис этой функции:
СохранениеПериодическихРеквизитов(<Режим>, <СписокРеквизитов>)
Где параметр <Режим> может принимать следующие значения:
Параметр <СписокРеквизитов> представляет собой строку с именами реквизитов через запятую, для которых настраивается режим. Если указать символ "*", настройка применится ко всем периодическим реквизитам формы.
Разберем по шагам, как применить это на практике. Откроем форму элемента справочника «Номенклатура» в конфигураторе, перейдем в модуль формы и в процедуре ПриОткрытии() пропишем следующую строку:
Процедура ПриОткрытии()
// Отключаем вывод диалога для реквизита СтавкаНДС, сохраняя его в "тихом" режиме
СохранениеПериодическихРеквизитов(2, "СтавкаНДС");
КонецПроцедуры
Такой подход решает проблему назойливого окна. Теперь при нажатии кнопки «ОК» значение будет записываться автоматически на текущую рабочую дату без лишних вопросов к пользователю.
Несмотря на простоту решения с режимом 2, у него есть существенный недостаток. При каждом пересохранении элемента справочника (например, если пользователь просто зашел в карточку изменить наименование, артикул или цену), платформа может продублировать запись значения периодического реквизита в системную таблицу истории _1SCONST на текущую дату, даже если сама ставка НДС не менялась. Со временем это приведет к лавинообразному росту базы данных и засорению истории ненужными дублирующими записями.
Чтобы избежать этой проблемы, профессиональные разработчики полностью отключают стандартный механизм сохранения периодики и реализуют запись вручную только при реальном изменении значения. Проанализируем, как реализовать этот алгоритм:
ПриОткрытии() полностью отключаем автосохранение, установив режим 0.ПриЗаписи() сравниваем текущее значение на форме с тем значением, которое уже сохранено в базе данных на рабочую дату.Периодический.Посмотрим на пример реализации данного алгоритма в модуле формы элемента номенклатуры:
Процедура ПриОткрытии()
// Полностью отключаем интерактивное сохранение периодических реквизитов
СохранениеПериодическихРеквизитов(0);
КонецПроцедуры
Процедура ПриЗаписи()
// Проверяем, что элемент уже существует в базе (не новый)
Если ТекущийЭлемент().Выбран() = 1 Тогда
// Получаем старое значение периодического реквизита на рабочую дату из БД
СтароеЗначение = ТекущийЭлемент().СтавкаНДС.Получить(РабочаяДата());
// Если значение на форме было реально изменено пользователем
Если СтароеЗначение <> СтавкаНДС Тогда
// Создаем объект для работы с периодическими реквизитами
ОбъектПериодический = СоздатьОбъект("Периодический");
// Инициализируем его для нашего реквизита и текущего элемента справочника
ОбъектПериодический.ИспользоватьОбъект("СтавкаНДС", ТекущийЭлемент());
// Устанавливаем дату и новое значение
ОбъектПериодический.ДатаЗнач = РабочаяДата();
ОбъектПериодический.Значение = СтавкаНДС;
// Записываем изменения в историю БД
ОбъектПериодический.Записать();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот программный код полностью защищает базу данных от появления дубликатов в истории и избавляет пользователей от диалоговых окон.
Несмотря на то, что технически мы решили проблему диалогов, само архитектурное решение сделать ставку НДС периодическим реквизитом в конфигурации «Торговля и Склад 7.7» таит в себе скрытые угрозы. Разберем подробнее, почему разработчики фирмы «1С» отказались от этого пути при переходе на новые ставки НДС:
_1SCONST. Если в вашей базе десятки или сотни тысяч позиций номенклатуры, создание периодических записей для каждой из них приведет к колоссальному росту этой таблицы. Это замедлит работу всей системы, особенно при проведении документов и формировании отчетов, так как получение периодического реквизита требует дополнительных SQL-запросов к одной и той же нагруженной таблице.ТекНоменклатура.СтавкаНДС при изменении его типа на периодический начнет возвращать не число или значение перечисления, а объект периодического реквизита. Чтобы получить само значение, вам придется переписать код абсолютно во всех этих местах на конструкцию вида ТекНоменклатура.СтавкаНДС.Получить(ДатаДок). Пропустить какое-то место чрезвычайно легко, что неминуемо приведет к критическим ошибкам в расчете налогов и сумм документов.Как же поступить правильно, если нужно учесть изменение законодательства (например, переход с 18% на 20%, а в перспективе и на другие ставки), сохранив при этом проведение старых документов без изменений?
Наиболее изящным и безопасным решением является подход, при котором реквизит в номенклатуре остается обычным статическим значением, а конкретная ставка НДС вычисляется динамически с помощью глобальной функции в зависимости от даты документа.
Проанализируем этот метод по шагам:
КатегорияНДС со значениями: ОсновнаяСтавка, ПониженнаяСтавка, БезНДС).Рассмотрим пример такой глобальной функции в глобальном модуле:
Функция глПолучитьСтавкуНДС(Номенклатура, ДатаДок) Экспорт
// Получаем категорию НДС, привязанную к номенклатуре
Категория = Номенклатура.КатегорияНДС;
// Если категория не заполнена, возвращаем ставку по умолчанию
Если ПустоеЗначение(Категория) = 1 Тогда
Возврат Перечисление.СтавкиНДС.НДС20; // Или актуальная на сегодня
КонецЕсли;
// Анализируем категорию
Если Категория = Перечисление.КатегорииНДС.БезНДС Тогда
Возврат Перечисление.СтавкиНДС.БезНДС;
ИначеЕсли Категория = Перечисление.КатегорииНДС.ПониженнаяСтавка Тогда
Возврат Перечисление.СтавкиНДС.НДС10;
ИначеЕсли Категория = Перечисление.КатегорииНДС.ОсновнаяСтавка Тогда
// Здесь прописываем временную шкалу изменения законодательства
Если ДатаДок < '01.01.2019' Тогда
Возврат Перечисление.СтавкиНДС.НДС18;
ИначеЕсли ДатаДок < '01.01.2026' Тогда
Возврат Перечисление.СтавкиНДС.НДС20;
Иначе
// Пример для будущих изменений ставок
Возврат Перечисление.СтавкиНДС.НДС22;
КонецЕсли;
КонецЕсли;
// Резервный возврат
Возврат Перечисление.СтавкиНДС.БезНДС;
КонецФункции
При таком подходе вам не нужно делать реквизиты периодическими и перегружать таблицу _1SCONST. Все старые документы за прошлые годы будут автоматически рассчитываться по исторически верным ставкам, а новые документы — по актуальной ставке. При этом база данных остается легкой, а код — чистым и легко поддерживаемым. В случае очередного изменения законодательства вам потребуется скорректировать код всего лишь в одном месте — внутри этой глобальной функции.
Мы надеемся, что данный детальный разбор помог вам определиться с оптимальной стратегией изменения ставок НДС в вашей конфигурации 1С 7.7 и успешно решить технические проблемы со всплывающими диалогами.