Почему при проведении документа в 1С выводится пустое сообщение об ошибке

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

При разработке механизмов проведения документов в системе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда транзакция проведения прерывается, платформа сообщает, что «Объект не проведен», но текст конкретной ошибки в окне сообщений отсутствует. Рассмотрим причины такого поведения системы, проанализируем типичный программный код и выясним, почему отладчик может вести себя непредсказуемо на строках обхода выборки запроса.

Разбор основной причины: отсутствие метода Сообщить()

Проанализируем ситуацию, описанную в теме. Разработчик создает объект СообщениеПользователю, заполняет его текст, но при выполнении кода пользователь не видит никакой информации. Основная ошибка заключается в том, что инициализация объекта Новый СообщениеПользователю лишь создает экземпляр сообщения в памяти, но не выводит его на экран. Для того чтобы сообщение попало в информационное окно, необходимо вызвать метод Сообщить().

Рассмотрим фрагмент проблемного кода:


Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрШаблон("Недостаточно товара %1 в количестве %2",
                  ВыборкаНоменклатура.НоменклатураПредставление, 
                  ВыборкаНоменклатура.Количество - ВыборкаНоменклатура.КоличествоОстаток);
// Ошибка: отсутствует вызов Сообщение.Сообщить();

В данном случае, когда переменная Отказ устанавливается в значение Истина, платформа понимает, что проведение должно быть прекращено. Однако, поскольку метод вывода сообщения не был вызван, очередь сообщений остается пустой, и пользователь получает лишь системное уведомление о факте непроведения объекта.

Особенности работы отладчика и выборки запроса

Выясним причину, по которой отладчик может «вылетать» или вести себя странно на строке Пока ВыборкаНоменклатура.Следующий() Цикл. В 1С метод Следующий() при обходе результата запроса ПоГруппировкам выполняет не только переход к следующей записи, но и обращение к агрегатным данным группировки. Если в результатах запроса содержатся некорректные данные или NULL, которые участвуют в расчете итогов, исключение может возникнуть именно в момент вызова Следующий().

Проанализируем запрос из примера. В нем используется ЛЕВОЕ СОЕДИНЕНИЕ с виртуальной таблицей остатков. Если номенклатуры нет на остатке, все поля из правой таблицы (включая количество, сумму и субконто) будут содержать NULL. Хотя автор использовал ЕСТЬNULL для числовых полей, поле Партия (Субконто3) остается равным NULL.

Посмотрим на условие упорядочивания в запросе:


УПОРЯДОЧИТЬ ПО
    ВЫРАЗИТЬ(УправленческийОстатки.Субконто3 КАК Документ.ПриходнаяНакладная).МоментВремени УБЫВ

Если Субконто3 равно NULL, попытка обращения к свойству МоментВремени через конструкцию ВЫРАЗИТЬ может приводить к нестабильной работе выборки на уровне СУБД или платформы. В некоторых случаях это вызывает неявную ошибку при получении данных следующей записи группировки.

Логические ошибки при контроле остатков

Разберем еще один важный момент: использование флага Отказ внутри цикла. Рассмотрим фрагмент кода:


Если ВыборкаНоменклатура.Количество > ВыборкаНоменклатура.КоличествоОстаток Тогда
    Отказ = Истина;
    // ... здесь вывод сообщения ...
КонецЕсли;

Если Отказ Тогда
    Продолжить;            
КонецЕсли;

С точки зрения методики «1С:Специалист», такая проверка должна выполняться максимально эффективно. Если обнаружена нехватка хотя бы по одной позиции, мы обязаны сообщить об этом пользователю. Однако продолжение цикла (Продолжить) после установки Отказ = Истина может быть опасно, если далее по тексту процедуры ОбработкаПроведения выполняются операции, зависящие от корректности данных (например, расчеты, где возможно деление на ноль).

Проблема кэширования метаданных и конфигурации

Иногда поведение системы (когда код ведет себя иначе, чем показывает отладчик) связано с «замусоренным» кэшем 1С. Это происходит при частом динамическом обновлении конфигурации базы данных. В таких случаях отладчик может позиционироваться на одной строке, в то время как фактически исполняется другая версия кода.

Для решения подобных «фантомных» проблем рекомендуется выполнить очистку кэша. Сделать это можно двумя способами:

  1. Вручную: удалить содержимое папок в каталогах %AppData%\1C\1Cv8 и %LocalAppData%\1C\1Cv8 (папки с длинными именами-идентификаторами).
  2. Автоматически: удалить базу из списка в окне запуска 1С и добавить её заново. Это приведет к созданию нового чистого каталога кэша для данной базы.

Рекомендованная структура процедуры ОбработкаПроведения

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // 1. Подготовка движений к записи
    Движения.Управленческий.Записывать = Истина;
    Движения.Записать();
    
    // 2. Установка блокировок
    Блокировка = Новый БлокировкаДанных;
    // ... настройка элементов блокировки ...
    Блокировка.Заблокировать();
    
    // 3. Выполнение запроса
    Запрос = Новый Запрос;
    // ... текст запроса с ЕСТЬNULL и правильными соединениями ...
    РезультатЗапроса = Запрос.Выполнить();
    
    // 4. Обход результатов
    ВыборкаНоменклатура = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    Пока ВыборкаНоменклатура.Следующий() Цикл
        
        // Сначала проверяем остатки
        Нехватка = ВыборкаНоменклатура.Количество - ВыборкаНоменклатура.КоличествоОстаток;
        Если Нехватка > 0 Тогда
            Отказ = Истина;
            Сообщение = Новый СообщениеПользователю;
            Сообщение.Текст = "Недостаточно товара " + ВыборкаНоменклатура.НоменклатураПредставление;
            Сообщение.Сообщить(); // ОБЯЗАТЕЛЬНЫЙ МЕТОД
        КонецЕсли;
        
        // Если уже есть отказ, расчеты по этой номенклатуре не проводим
        Если Отказ Тогда
            Продолжить;
        КонецЕсли;
        
        // 5. Алгоритм списания (ФИФО/ЛИФО)
        КоличествоСписать = ВыборкаНоменклатура.Количество;
        ВыборкаДетальныеЗаписи = ВыборкаНоменклатура.Выбрать();
        
        Пока ВыборкаДетальныеЗаписи.Следующий() И КоличествоСписать > 0 Цикл
            // ... логика расчета себестоимости и добавления движений ...
        КонецЦикла;
        
    КонецЦикла;
    
КонецПроцедуры

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

← На главную