Как эффективно запретить незаполненные значения в 1С и почему стандартные механизмы могут не срабатывать?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей
← К списку

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

Разграничиваем понятия: ПроверкаЗаполнения и ЗапретНезаполненныхЗначений

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

  1. Свойство ПроверкаЗаполнения (устанавливается в "Выдавать ошибку")

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

    • Если поле не заполнено, а свойство установлено, пользователь получит сообщение об ошибке, и документ не будет проведен (или элемент справочника не будет записан).
    • Важный момент: При программном формировании или проведении документа, а также при программной записи регистра, свойство ПроверкаЗаполнения не анализируется и данная проверка не срабатывает.
    • Использование этого механизма удобно для отсечения ошибок на ранних этапах ввода данных пользователем, что требует меньше системных ресурсов.
  2. Свойство ЗапретНезаполненныхЗначений (устанавливается в "Истина")

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

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

Таким образом, если незаполненными оказываются измерения регистра, и для них установлено свойство ЗапретНезаполненныхЗначений, но записи все равно появляются, то причина кроется в обходе этой проверки.

Выясняем причину: Почему ЗапретНезаполненныхЗначений может быть обойден?

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

  1. Флаг ОбменДанными.Загрузка = Истина

    Это наиболее частая причина обхода проверок. В платформе 1С существует глобальный флаг ОбменДанными.Загрузка. Если этот флаг установлен в значение Истина, то большинство проверок, включая ЗапретНезаполненныхЗначений, а также проверки в обработчиках событий ПередЗаписью и подписках на события, отключаются. Этот режим используется для загрузки данных "как есть" из других систем или узлов обмена, предполагая, что данные уже были проверены на источнике.

    • Как это работает? При программной записи данных в регистр, если перед вызовом метода Записать() или Записать() набора записей был установлен ОбменДанными.Загрузка = Истина, система игнорирует большинство внутренних проверок.
    • Где искать? Нам необходимо проанализировать код конфигурации. Ищите конструкции вида ОбменДанными.Загрузка = Истина в модулях объектов, модулях менеджеров, общих модулях, особенно в тех, которые отвечают за загрузку данных, синхронизацию или создание объектов программно.
    • Пример кода, который обходит проверку:
      
      Если УсловиеЗагрузкиИзОбмена Тогда
          ОбменДанными.Загрузка = Истина;
      КонецЕсли;
                      
      Попытка
          НаборЗаписейРегистра = РегистрыСведений.МойРегистр.СоздатьНаборЗаписей();
          // ... Заполняем измерения и ресурсы ...
          НаборЗаписейРегистра.Записать();
      Исключение
          // Обработка исключения
      КонецПопытки;
                      
      Если УсловиеЗагрузкиИзОбмена Тогда
          ОбменДанными.Загрузка = Ложь; // Важно сбросить флаг!
      КонецЕсли;
      
    • Важный момент: При использовании флага ОбменДанными.Загрузка = Истина вызывающая сторона (программист, разработчик) берет на себя полную ответственность за целостность и корректность загружаемых данных. Если вы обнаружили такой код, но не уверены в источнике данных или его проверках, вам следует пересмотреть логику.

Разбираемся с ресурсами: Что делать, если незаполнен ресурс?

Мы выяснили, что свойство ЗапретНезаполненныхЗначений применимо только к измерениям регистров. Что же делать, если пустые значения появляются в ресурсах регистров или в обычных реквизитах документов/справочников при программной записи?

Для ресурсов и реквизитов, помимо интерактивной проверки ПроверкаЗаполнения, нам потребуется реализовать собственные механизмы контроля, которые будут работать при программной записи:

  1. Программные проверки в модулях объектов

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

    
    // В модуле объекта регистра или документа
    Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
        Если Не ОбменДанными.Загрузка Тогда // Игнорируем проверки при загрузке данных
            Если ЭтоНовый() И ЗначениеЗаполнено(ЭтотОбъект.МойРесурс) = Ложь Тогда
                Сообщить("Ресурс 'МойРесурс' должен быть заполнен!");
                Отказ = Истина;
            КонецЕсли;
            // Или для изменения существующих
            Если Не ЭтоНовый() Тогда
                Если ЗначениеЗаполнено(ЭтотОбъект.МойРесурс) = Ложь Тогда
                    Сообщить("Ресурс 'МойРесурс' не может быть пустым!");
                    Отказ = Истина;
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецПроцедуры
    

    Обратите внимание, что здесь мы также проверяем флаг ОбменДанными.Загрузка, чтобы избежать конфликтов при загрузке данных.

  2. Подписки на события

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

Комплексное решение: Как обеспечить надежную проверку?

Чтобы полностью контролировать заполнение значений и избежать нежелательных пустых полей, мы предлагаем комплексный подход. Разберем его по шагам.

  1. Шаг 1: Проверяем настройки свойства ЗапретНезаполненныхЗначений

    Убедимся, что для всех критически важных измерений регистров, которые не должны быть пустыми, свойство ЗапретНезаполненныхЗначений установлено в "Истина". Это базовый уровень защиты.

    Как проверить: Откройте конфигуратор, перейдите в ветку "Регистры сведений" или "Регистры накопления" (или другие типы регистров), выберите нужный регистр, откройте его структуру. Для каждого измерения проверьте значение свойства "Запрет незаполненных значений".

  2. Шаг 2: Ищем места установки ОбменДанными.Загрузка = Истина

    Это самый критичный шаг. Мы должны найти все участки кода, где программно устанавливается флаг ОбменДанными.Загрузка = Истина, особенно если они предшествуют записи в регистры, где требуется строгий контроль заполнения.

    • Как искать: В конфигураторе используйте "Поиск по всей конфигурации" (Ctrl+Shift+F) по строке ОбменДанными.Загрузка = Истина.
    • Проанализируем ситуацию: Для каждого найденного участка кода выясним, почему используется этот флаг.
      • Если это модуль обмена или загрузки данных, и вы уверены, что источник данных гарантирует их целостность, то, возможно, это оправдано.
      • Если же это внутренний код конфигурации, не связанный с внешним обменом, то, вероятно, это ошибка или неоптимальное решение, которое следует пересмотреть.
    • Что делать: Если установка ОбменДанными.Загрузка = Истина не оправдана, следует удалить или закомментировать эти строки. Если же она необходима, но при этом требуется контроль заполнения, переходим к Шагу 3.
  3. Шаг 3: Используем подписки на события для кастомной проверки

    Подписки на события — это мощный инструмент для реализации собственной логики проверки, которая будет срабатывать независимо от того, как происходит запись (интерактивно или программно) и даже с учетом флага ОбменДанными.Загрузка (если мы явно это укажем).

    • Когда нужны подписки:
      • Для проверки заполнения ресурсов регистров или реквизитов документов/справочников при программной записи.
      • Если стандартный ЗапретНезаполненныхЗначений обходится из-за ОбменДанными.Загрузка = Истина, но вам все равно нужна проверка.
      • Для реализации более сложной логики проверки, чем просто "поле не пустое".
    • Как создать подписку:
      • В конфигураторе создайте новый объект "Подписка на событие".
      • Укажите "Источник" (например, "НаборЗаписей.РегистрСведений.МойРегистр" или "ДокументОбъект.РасходнаяНакладная").
      • Выберите "Событие" (например, "ПередЗаписью").
      • Укажите "Обработчик" – это будет процедура в общем модуле, которую вы создадите.
    • Пример кода обработчика подписки с учетом ОбменДанными.Загрузка:
      
      // В Общем модуле (например, "МоиПроверки")
      Процедура ПередЗаписьюРегистраМойРегистр(Источник, Отказ) Экспорт
          // Источник в данном случае - это набор записей регистра
          // Проверяем, не происходит ли загрузка данных через обмен
          Если Не ОбменДанными.Загрузка Тогда
              Для Каждого ЗаписьРегистра Из Источник Цикл
                  // Проверяем заполнение измерения, если стандартный ЗапретНезаполненныхЗначений
                  // по какой-то причине не сработал или был обойден.
                  // Хотя для измерений лучше полагаться на встроенный механизм, если он не обойден.
                  Если ЗначениеЗаполнено(ЗаписьРегистра.МоеИзмерение) = Ложь Тогда
                      Сообщить("Измерение 'МоеИзмерение' в регистре '" + Источник.Имя + "' не заполнено!");
                      Отказ = Истина;
                      Возврат; // Прекращаем проверку и запись
                  КонецЕсли;
                                  
                  // Проверяем заполнение ресурса, для которого нет ЗапретаНезаполненныхЗначений
                  Если ЗначениеЗаполнено(ЗаписьРегистра.МойРесурс) = Ложь Тогда
                      Сообщить("Ресурс 'МойРесурс' в регистре '" + Источник.Имя + "' не заполнен!");
                      Отказ = Истина;
                      Возврат; // Прекращаем проверку и запись
                  КонецЕсли;
              КонецЦикла;
          КонецЕсли;
      КонецПроцедуры
      
    • Рекомендация: В обработчиках событий ПередЗаписью и подписках на события, следуя стандартам разработки 1С, всегда выполняйте бизнес-логику и проверки после проверки Если Не ОбменДанными.Загрузка Тогда. Это гарантирует, что при загрузке данных через обмен не будет непредвиденных ошибок.

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

← К списку