Почему в отчете 1С 7.7 выводится замечание об отсутствии цены при ее наличии

Программист 1С v7.7 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При разработке отчетов и печатных форм в среде 1С:Предприятие 7.7 разработчики нередко сталкиваются с ситуацией, когда секция таблицы выводит предупреждение (например, «Не указана цена»), даже если реквизит заполнен и значение отлично от нуля. Разберем по шагам, из-за чего возникает такое поведение, как локализовать скрытые ошибки в коде и как грамотно переписать логику формирования отчета.

Анализ основных причин некорректного вывода данных

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

  1. Ошибки в логике ветвления Если ... ИначеЕсли: если в блоке ИначеЕсли жестко прописано присвоение служебного текста без вложенной проверки самого значения цены, программа гарантированно выведет эту строку при невыполнении главного условия Если.
  2. Использование пустых блоков Попытка ... Исключение: перехват ошибок без вывода сообщений маскирует реальные сбои (например, обращение к несуществующему реквизиту справочника вроде Спр.Механик). В результате выполнение блока прерывается на середине, а переменные остаются в неопределенном состоянии либо управление уходит по неверной ветке.
  3. Неочищенные переменные печатных секций: если перед проверкой условий переменным ПечНаименование и ПечЗамечание не присваиваются пустые значения, в секцию попадают данные от предыдущей итерации цикла.
  4. Неоптимальное обращение к периодическим реквизитам: постоянный вызов метода Получить(ТекущаяДата()) для каждого реквизита создает избыточные запросы к базе данных и усложняет чтение кода.

Пошаговый поиск и устранение ошибок

Рассмотрим последовательность действий, которая позволяет быстро выявить и устранить проблему в модуле отчета.

  1. Отключаем скрывающие блоки Попытка ... Исключение: убираем конструкцию перехвата ошибок, чтобы отладчик платформы сразу указал на строку с обращением к отсутствующему свойству или методу агрегатного объекта.
  2. Проверяем наличие реквизитов в метаданных: убеждаемся, что все используемые реквизиты (например, Механик, Сотрудник, НаОбслуживании) действительно присутствуют в структуре справочника.
  3. Выносим повторяющийся вывод секций в отдельную процедуру: это устраняет дублирование кода вывода секций Группировка и Строка и предотвращает рассинхронизацию условий.
  4. Устанавливаем дату выборки периодических реквизитов: перед циклом обхода справочника применяем метод ИспользоватьДату().

Оптимизация работы с периодическими реквизитами

Выясним причину замедления и возможных сбоев при чтении периодических реквизитов справочников. При вызове Спр.Цена.Получить(ТекущаяДата()) на каждом шаге цикла система выполняет отдельное обращение к таблице периодики. Гораздо надежнее и быстрее зафиксировать рабочую дату для самого объекта выборки с помощью метода ИспользоватьДату(ТекущаяДата(), 1).

Посмотрим на пример установки контекста даты:


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

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


Период = СоздатьОбъект("Периодический");
Период.ИспользоватьОбъект("Цена", Спр.ТекущийЭлемент());
Период.Получить(ТекущаяДата());
ЗначениеЦены = Период.Значение;

Рефакторинг и итоговый пример правильного кода

Разберем готовое решение, в котором устранены логические ошибки ветвления, вынесен в процедуру вывод секций таблицы и корректно проверяются все реквизиты объекта.


Перем Спр, Заголовок;

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

// Основной блок выборки и анализа данных
Процедура СформироватьОтчет()
    Таб.ИсходнаяТаблица("Таблица");
    
    Спр = СоздатьОбъект("Справочник.Оборудование");
    Спр.ИспользоватьДату(ТекущаяДата(), 1);
    Спр.ВыбратьЭлементы();
    
    Пока Спр.ПолучитьЭлемент() = 1 Цикл
        // Пропускаем удаленные элементы и объекты не на обслуживании
        Если (Спр.ПометкаУдаления() = 1) ИЛИ (Спр.НаОбслуживании = 0) Тогда
            Продолжить;
        КонецЕсли;
        
        Заголовок = 0;
        ПечОбъект = "Договор ТО №" + СокрЛП(СпрДоговоры.НомерДоговора) + 
                    " (" + СпрДоговоры.Контрагент.Наименование + "), модель " + 
                    Спр.Модель.Наименование + " (№" + СокрЛП(Спр.СерийныйНомер.ЗаводскойНомер) + ")";
        
        // 1. Проверка телефонов
        Если (Спр.Телефон1 = "8(   )   -  -  ") И (Спр.Телефон2 = "8(   )   -  -  ") И 
             (Спр.Телефон3 = "8(   )   -  -  ") И (Спр.Телефон4 = "8(   )   -  -  ") Тогда
            ВывестиЗамечание("   Телефоны", "Не указан телефон.");
        КонецЕсли;
        
        // 2. Проверка даты замены ЭКЛЗ
        Если ПустоеЗначение(Спр.ДатаЗаменыЭКЛЗ) = 1 Тогда
            ВывестиЗамечание("   ЭКЛЗ", "Дата блокировки ЭКЛЗ не указана.");
        ИначеЕсли Спр.ДатаЗаменыЭКЛЗ < ТекущаяДата() Тогда
            ВывестиЗамечание("   ЭКЛЗ", "Просрочена дата замены ЭКЛЗ.");
        КонецЕсли;
        
        // 3. Проверка адреса эксплуатации
        Если ПустоеЗначение(Спр.МестоУстановки.АдресФакт) = 1 Тогда
            ВывестиЗамечание("   Адрес эксплуатации", "Не указан адрес места эксплуатации.");
        КонецЕсли;
        
        // 4. Проверка станции метро
        Если ПустоеЗначение(Спр.МестоУстановки.Метро) = 1 Тогда
            ВывестиЗамечание("   Метро", "Не указана станция метро места эксплуатации.");
        КонецЕсли;
        
        // 5. Проверка ИФНС
        Если ПустоеЗначение(Спр.ИФНС) = 1 Тогда
            ВывестиЗамечание("   ИФНС", "Не указан ИФНС.");
        ИначеЕсли ПустоеЗначение(Спр.ИФНС.Адрес) = 1 Тогда
            ВывестиЗамечание("   ИФНС", "Не указан адрес ИФНС.");
        КонецЕсли;
        
        // 6. Проверка цены (срабатывает строго при нулевой или незаполненной цене)
        Если (ПустоеЗначение(Спр.Цена) = 1) ИЛИ (Спр.Цена = 0) Тогда
            ВывестиЗамечание("   Цена", "Не указана цена.");
        КонецЕсли;
        
    КонецЦикла;
    
    Таб.Показать("Отчет по замечаниям");
КонецПроцедуры

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

← На главную